home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / JTree.java < prev    next >
Text File  |  1998-06-30  |  127KB  |  3,513 lines

  1. /*
  2.  * @(#)JTree.java    1.75 98/04/01
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing;
  22.  
  23. import java.awt.*;
  24. import java.awt.event.*;
  25. import java.beans.*;
  26. import java.io.*;
  27. import java.util.*;
  28. import com.sun.java.swing.event.*;
  29. import com.sun.java.swing.plaf.TreeUI;
  30. import com.sun.java.swing.tree.*;
  31. import com.sun.java.accessibility.*;
  32.  
  33.  
  34. /**
  35.  * A control that displays a set of hierarchical data as an outline.
  36.  * A specific node can be identified either by a TreePath (an object
  37.  * that encapsulates a node and all of its ancestors), or by its
  38.  * display row, where each row in the display area displays one node.
  39.  * <p>
  40.  * An <i>expanded</i> node is one displays its children. A <i>collapsed</i>
  41.  * node is one which hides them. A <i>visible</i> node is one which
  42.  * is currently viewable in the display area.
  43.  * <p>
  44.  * If you are interested in knowing when the selection changes implement
  45.  * the TreeSelectionListener interface and add the instance using the
  46.  * method addTreeSelectionListener. valueChanged will be invoked when the
  47.  * selection changes, that is if the user clicks twice on the same
  48.  * node valueChanged will only be invoked once.
  49.  * <p>
  50.  * If you are interested in knowing either double clicks events or when
  51.  * a user clicks on a node, regardless of whether or not it was selected
  52.  * it is recommended you do the following:
  53.  * <pre>
  54.  * final JTree tree = ...;
  55.  *
  56.  * MouseListener ml = new MouseAdapter() {
  57.  *     public void <b>mouseClicked</b>(MouseEvent e) {
  58.  *         int selRow = tree.getRowForLocation(e.getX(), e.getY());
  59.  *         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
  60.  *         if(selRow != -1) {
  61.  *             if(e.getClickCount() == 1) {
  62.  *                 mySingleClick(selRow, selPath);
  63.  *             }
  64.  *             else if(e.getClickCount() == 2) {
  65.  *                 myDoubleClick(selRow, selPath);
  66.  *             }
  67.  *         }
  68.  *     }
  69.  * };
  70.  * tree.addMouseListener(ml);
  71.  *</pre>
  72.  * NOTE: This example obtains both the path and row, but you only need to
  73.  * get the one you're interested in.
  74.  * <p>
  75.  * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/tree.html">How to Use Trees</a>
  76.  * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  77.  * for further documentation.
  78.  * <p>
  79.  * For the keyboard keys used by this component in the standard Look and
  80.  * Feel (L&F) renditions, see the
  81.  * <a href="doc-files/Key-Index.html#JTree">JTree</a> key assignments.
  82.  * <p>
  83.  * Warning: serialized objects of this class will not be compatible with
  84.  * future swing releases.  The current serialization support is appropriate
  85.  * for short term storage or RMI between Swing1.0 applications.  It will
  86.  * not be possible to load serialized Swing1.0 objects with future releases
  87.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  88.  * baseline for the serialized form of Swing objects.
  89.  *
  90.  * @beaninfo
  91.  *   attribute: isContainer false
  92.  *
  93.  * @version 1.75 04/01/98
  94.  * @author Rob Davis
  95.  * @author Ray Ryan
  96.  * @author Scott Violet
  97.  */
  98. public class JTree extends JComponent implements Scrollable, Accessible
  99. {
  100.     /**
  101.      * The model that defines the tree displayed by this object.
  102.      */
  103.     transient protected TreeModel                treeModel;
  104.  
  105.     /**
  106.      * Models the set of selected nodes in this tree.
  107.      */
  108.     transient protected TreeSelectionModel selectionModel;
  109.  
  110.     /**
  111.      * True if the root node is displayed, false if its children are
  112.      * the highest visible nodes.
  113.      */
  114.     protected boolean            rootVisible;
  115.  
  116.     /**
  117.      * The cell used to draw nodes. If null, the UI uses a default
  118.      * cellRenderer.
  119.      */
  120.     transient protected TreeCellRenderer        cellRenderer;
  121.  
  122.     /**
  123.      * Height to use for each display row. If this is <= 0 the renderer 
  124.      * determines the height for each row.
  125.      */
  126.     protected int               rowHeight;
  127.  
  128.     /**
  129.      * True if handles are displayed at the topmost level of the tree.
  130.      * <p>
  131.      * A handle is a small icon that displays adjacent to the node which 
  132.      * allows the user to click once to expand or collapse the node. A
  133.      * common interface shows a plus sign (+) for a node which can be
  134.      * expanded and a minus sign (-) for a node which can be collapsed.
  135.      * Handles are always shown for nodes below the topmost level.
  136.      * <p>
  137.      * If the <code>rootVisible</code> setting specifies that the root 
  138.      * node is to be displayed, then that is the only node at the topmost
  139.      * level. If the root node is not displayed, then all of its 
  140.      * children are at the topmost level of the tree. Handles are 
  141.      * always displayed for nodes other than the topmost.
  142.      * <p> 
  143.      * If the root node isn't visible, it is generally a good to make 
  144.      * this value true. Otherwise, the tree looks exactly like a list,
  145.      * and users may not know that the "list entries" are actually
  146.      * tree nodes.
  147.      *
  148.      * @see #rootVisible
  149.      */
  150.     protected boolean           showsRootHandles;
  151.  
  152.     /**
  153.      * Creates a new event and passed it off the selectionListeners.
  154.      */
  155.     protected TreeSelectionRedirector selectionRedirector;
  156.  
  157.     /**
  158.      * Editor for the entries.  Default is null (tree is not editable).
  159.      */
  160.     transient protected TreeCellEditor          cellEditor;
  161.  
  162.     /**
  163.      * Is the tree editable? Default is false.
  164.      */
  165.     protected boolean                 editable;
  166.  
  167.     /**
  168.      * Is this tree a large model? This is a code-optimization setting.
  169.      * A large model can be used when the cell height is the same for all
  170.      * nodes. The UI will then cache very little information and instead
  171.      * continually message the model. Without a large model the UI caches 
  172.      * most of the information, resulting in fewer method calls to the model.
  173.      * <p>
  174.      * This value is only a suggestion to the UI. Not all UIs will
  175.      * take advantage of it. Default value is false.
  176.      */
  177.     protected boolean                 largeModel;
  178.  
  179.     /**
  180.      * Number of rows to make visible at one time. This value is used for
  181.      * the Scrollable interface. It determines the preferred size of the 
  182.      * display area.
  183.      */
  184.     protected int                     visibleRowCount;
  185.  
  186.     /**
  187.      * If true, when editing is to be stopped by way of selection changing,
  188.      * data in tree changing or other means stopCellEditing is invoked, and
  189.      * changes are saved. If false, cancelCellEditing is invoked, and changes
  190.      * are discarded. Default is false.
  191.      */
  192.     protected boolean                 invokesStopCellEditing;
  193.  
  194.     //
  195.     // Bound propery names
  196.     //
  197.     /** Bound property name for cellRenderer. */
  198.     public final static String        CELL_RENDERER_PROPERTY = "cellRenderer";
  199.     /** Bound property name for treeModel. */
  200.     public final static String        TREE_MODEL_PROPERTY = "treeModel";
  201.     /** Bound property name for rootVisible. */
  202.     public final static String        ROOT_VISIBLE_PROPERTY = "rootVisible";
  203.     /** Bound property name for showsRootHandles. */
  204.     public final static String        SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
  205.     /** Bound property name for rowHeight. */
  206.     public final static String        ROW_HEIGHT_PROPERTY = "rowHeight";
  207.     /** Bound property name for cellEditor. */
  208.     public final static String        CELL_EDITOR_PROPERTY = "cellEditor";
  209.     /** Bound property name for editable. */
  210.     public final static String        EDITABLE_PROPERTY = "editable";
  211.     /** Bound property name for largeModel. */
  212.     public final static String        LARGE_MODEL_PROPERTY = "largeModel";
  213.     /** Bound property name for selectionModel. */
  214.     public final static String        SELECTION_MODEL_PROPERTY = "selectionModel";
  215.     /** Bound property name for visibleRowCount. */
  216.     public final static String        VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
  217.     /** Bound property name for messagesStopCellEditing. */
  218.     public final static String        INVOKES_STOP_CELL_EDITING_PROPERTY = "messagesStopCellEditing";
  219.  
  220.  
  221.     /**
  222.      * Creates and returns a sample TreeModel. Used primarily for beanbuilders.
  223.      * to show something interesting.
  224.      *
  225.      * @return the default TreeModel
  226.      */
  227.     protected static TreeModel getDefaultTreeModel() {
  228.         DefaultMutableTreeNode      root = new DefaultMutableTreeNode("root");
  229.         DefaultMutableTreeNode      parent, child;
  230.  
  231.         parent = root;
  232.         child = new DefaultMutableTreeNode("swing");
  233.         parent.add(child);
  234.         parent = child;
  235.         child = new DefaultMutableTreeNode("is");
  236.         parent.add(child);
  237.         parent = child;
  238.         child = new DefaultMutableTreeNode("cool");
  239.         parent.add(child);
  240.         return new DefaultTreeModel(root);
  241.     }
  242.  
  243.     /**
  244.      * Returns a TreeModel wrapping the specified object. If the object
  245.      * is:<ul>
  246.      * <li>an array of Objects,
  247.      * <li>a Hashtable, or
  248.      * <li>a Vector
  249.      * </ul>then a new root node is created with each of the incoming 
  250.      * objects as children. Otherwise, a new root is created with the 
  251.      * specified object as its value.
  252.      *
  253.      * @param value  the Object used as the foundation for the TreeModel
  254.      * @return a TreeModel wrapping the specified object
  255.      */
  256.     protected static TreeModel createTreeModel(Object value) {
  257.         DefaultMutableTreeNode           root;
  258.  
  259.         if((value instanceof Object[]) || (value instanceof Hashtable) ||
  260.            (value instanceof Vector)) {
  261.             root = new DefaultMutableTreeNode("root");
  262.             DynamicUtilTreeNode.createChildren(root, value);
  263.         }
  264.         else {
  265.             root = new DynamicUtilTreeNode("root", value);
  266.         }
  267.         return new DefaultTreeModel(root, false);
  268.     }
  269.  
  270.     /**
  271.      * Returns a JTree with a sample model.
  272.      *
  273.      * @return a JTree with the default model, which defines a leaf node
  274.      *         as any node without children.
  275.      * @see DefaultTreeModel#asksAllowsChildren
  276.      */
  277.     public JTree() {
  278.         this(getDefaultTreeModel());
  279.     }
  280.  
  281.     /**
  282.      * Returns a JTree with each element of the specified array as the
  283.      * child of a new root node which is not displayed.
  284.      * By default, the tree defines a leaf node as any node without
  285.      * children.
  286.      *
  287.      * @param value  an array of Objects
  288.      * @return a JTree with the contents of the array as children of
  289.      *         the root node
  290.      * @see DefaultTreeModel#asksAllowsChildren
  291.      */
  292.     public JTree(Object[] value) {
  293.         this(createTreeModel(value));
  294.         this.setRootVisible(false);
  295.         this.setShowsRootHandles(true);
  296.     }
  297.  
  298.     /**
  299.      * Returns a JTree with each element of the specified Vector as the
  300.      * child of a new root node which is not displayed. By default, the
  301.      * tree defines a leaf node as any node without children.
  302.      *
  303.      * @param value  a Vector
  304.      * @return a JTree with the contents of the Vector as children of
  305.      *         the root node
  306.      * @see DefaultTreeModel#asksAllowsChildren
  307.      */
  308.     public JTree(Vector value) {
  309.         this(createTreeModel(value));
  310.         this.setRootVisible(false);
  311.         this.setShowsRootHandles(true);
  312.     }
  313.  
  314.     /**
  315.      * Returns a JTree created from a Hashtable which does not display
  316.      * the root. Each value-half of the key/value pairs in the HashTable
  317.      * becomes a child of the new root node. By default, the tree defines
  318.      * a leaf node as any node without children.
  319.      *
  320.      * @param value  a Hashtable
  321.      * @return a JTree with the contents of the Hashtable as children of
  322.      *         the root node
  323.      * @see DefaultTreeModel#asksAllowsChildren
  324.      */
  325.     public JTree(Hashtable value) {
  326.         this(createTreeModel(value));
  327.         this.setRootVisible(false);
  328.         this.setShowsRootHandles(true);
  329.     }
  330.  
  331.     /**
  332.      * Returns a JTree with the specified TreeNode as its root which is 
  333.      * not displayed. By default, the tree defines a leaf node as any node
  334.      * without children.
  335.      *
  336.      * @param root  a TreeNode object
  337.      * @return a JTree with the specified root node
  338.      * @see DefaultTreeModel#asksAllowsChildren
  339.      */
  340.     public JTree(TreeNode root) {
  341.         this(root, false);
  342.     }
  343.  
  344.     /**
  345.      * Returns a JTree with the specified TreeNode as its root, which 
  346.      * displays the root node and which decides whether a node is a 
  347.      * leaf node in the specified manner.
  348.      *
  349.      * @param root  a TreeNode object
  350.      * @param asksAllowsChildren  if false, any node without children is a 
  351.      *              leaf node. If true, only nodes that do not allow 
  352.      *              children are leaf nodes.
  353.      * @return a JTree with the specified root node
  354.      * @see DefaultTreeModel#asksAllowsChildren
  355.      */
  356.     public JTree(TreeNode root, boolean asksAllowsChildren) {
  357.         this(new DefaultTreeModel(root, asksAllowsChildren));
  358.     }
  359.  
  360.     /**
  361.      * Returns an instance of JTree which displays the root node 
  362.      * -- the tree is created using the specified data model.
  363.      *
  364.      * @param newModel  the TreeModel to use as the data model
  365.      * @return a JTree based on the TreeModel
  366.      */
  367.     public JTree(TreeModel newModel) {
  368.         super();
  369.         setLayout(null);
  370.         rowHeight = 16;
  371.         visibleRowCount = 20;
  372.         rootVisible = true;
  373.         selectionModel = new DefaultTreeSelectionModel();
  374.         cellRenderer = null;
  375.         updateUI();
  376.         setModel(newModel);
  377.     }
  378.  
  379.     /**
  380.      * Returns the L&F object that renders this component.
  381.      *
  382.      * @return the TreeUI object that renders this component
  383.      */
  384.     public TreeUI getUI() {
  385.         return (TreeUI)ui;
  386.     }
  387.  
  388.     /**
  389.      * Sets the L&F object that renders this component.
  390.      *
  391.      * @param ui  the TreeUI L&F object
  392.      * @see UIDefaults#getUI
  393.      */
  394.     public void setUI(TreeUI ui) {
  395.         if ((TreeUI)this.ui != ui) {
  396.             super.setUI(ui);
  397.             repaint();
  398.         }
  399.     }
  400.  
  401.     /**
  402.      * Notification from the UIManager that the L&F has changed. 
  403.      * Replaces the current UI object with the latest version from the 
  404.      * UIManager.
  405.      *
  406.      * @see JComponent#updateUI
  407.      */
  408.     public void updateUI() {
  409.         setUI((TreeUI)UIManager.getUI(this));
  410.         invalidate();
  411.     }
  412.  
  413.  
  414.     /**
  415.      * Returns the name of the L&F class that renders this component.
  416.      *
  417.      * @return "TreeUI"
  418.      * @see JComponent#getUIClassID
  419.      * @see UIDefaults#getUI
  420.      */
  421.     public String getUIClassID() {
  422.         return "TreeUI";
  423.     }
  424.  
  425.  
  426.     /**
  427.      * Returns the current TreeCellRenderer that is rendering each cell.
  428.      *
  429.      * @return the TreeCellRenderer that is rendering each cell
  430.      */
  431.     public TreeCellRenderer getCellRenderer() {
  432.         return cellRenderer;
  433.     }
  434.  
  435.     /**
  436.      * Sets the TreeCellRenderer that will be used to draw each cell.
  437.      *
  438.      * @param x  the TreeCellRenderer that is to render each cell
  439.      * @beaninfo
  440.      *        bound: true
  441.      *  description: The TreeCellRenderer that will be used to draw
  442.      *               each cell.
  443.      */
  444.     public void setCellRenderer(TreeCellRenderer x) {
  445.         TreeCellRenderer oldValue = cellRenderer;
  446.  
  447.         cellRenderer = x;
  448.         firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, cellRenderer);
  449.         invalidate();
  450.     }
  451.  
  452.     /**
  453.       * Determines whether the tree is editable. Fires a property
  454.       * change event if the new setting is different from the existing
  455.       * setting.
  456.       *
  457.       * @param flag  a boolean value, true if the tree is editable
  458.       * @beaninfo
  459.       *        bound: true
  460.       *  description: Whether the tree is editable.
  461.       */
  462.     public void setEditable(boolean flag) {
  463.         boolean                 oldValue = this.editable;
  464.  
  465.         this.editable = flag;
  466.         firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
  467.         if (accessibleContext != null) {
  468.             accessibleContext.firePropertyChange(
  469.                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 
  470.                 (oldValue ? AccessibleState.EDITABLE : null),
  471.                 (flag ? AccessibleState.EDITABLE : null));
  472.         }
  473.     }
  474.  
  475.     /**
  476.      * Returns true if the tree is editable.
  477.      *
  478.      * @return true if the tree is editable.
  479.      */
  480.     public boolean isEditable() {
  481.         return editable;
  482.     }
  483.  
  484.     /**
  485.      * Sets the cell editor.  A null value implies that the
  486.      * tree cannot be edited.  If this represents a change in the
  487.      * cellEditor, the propertyChange method is invoked on all
  488.      * listeners.
  489.      *
  490.      * @param cellEditor the TreeCellEditor to use
  491.      * @beaninfo
  492.      *        bound: true
  493.      *  description: The cell editor. A null value implies the tree
  494.      *               cannot be edited.
  495.      */
  496.     public void setCellEditor(TreeCellEditor cellEditor) {
  497.         TreeCellEditor        oldEditor = this.cellEditor;
  498.  
  499.         this.cellEditor = cellEditor;
  500.         firePropertyChange(CELL_EDITOR_PROPERTY, oldEditor, cellEditor);
  501.         invalidate();
  502.     }
  503.  
  504.     /**
  505.      * Returns the editor used to edit entries in the tree.
  506.      *
  507.      * @return the TreeCellEditor in use, or null if the tree cannot
  508.      *         be edited
  509.      */
  510.     public TreeCellEditor getCellEditor() {
  511.         return cellEditor;
  512.     }
  513.  
  514.     /**
  515.      * Returns the TreeModel that is providing the data.
  516.      *
  517.      * @return the TreeModel that is providing the data
  518.      */
  519.     public TreeModel getModel() {
  520.         return treeModel;
  521.     }
  522.  
  523.     /**
  524.      * Sets the TreeModel that will provide the data.
  525.      *
  526.      * @param newModel the TreeModel that is to provide the data
  527.      * @beaninfo
  528.      *        bound: true
  529.      *  description: The TreeModel that will provide the data.
  530.      */
  531.     public void setModel(TreeModel newModel) {
  532.         TreeModel oldModel = treeModel;
  533.         
  534.         treeModel = newModel;
  535.         firePropertyChange(TREE_MODEL_PROPERTY, oldModel, treeModel);
  536.         invalidate();
  537.     }
  538.  
  539.     /**
  540.      * Returns true if the root node of the tree is displayed.
  541.      *
  542.      * @return true if the root node of the tree is displayed
  543.      * @see #rootVisible
  544.      */
  545.     public boolean isRootVisible() {
  546.         return rootVisible;
  547.     }
  548.  
  549.     /**
  550.      * Determines whether or not the root node from
  551.      * the TreeModel is visible.
  552.      *
  553.      * @param rootVisible true if the root node of the tree is to be displayed
  554.      * @see #rootVisible
  555.      * @beaninfo
  556.      *        bound: true
  557.      *  description: Whether or not the root node 
  558.      *               from the TreeModel is visible.
  559.      */
  560.     public void setRootVisible(boolean rootVisible) {
  561.         boolean                oldValue = this.rootVisible;
  562.  
  563.         this.rootVisible = rootVisible;
  564.         firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, this.rootVisible);
  565.         if (accessibleContext != null) {
  566.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  567.         }
  568.     }
  569.  
  570.     /**
  571.      * Determines whether the node handles are to be displayed.
  572.      * 
  573.      * @param newValue true if root handles are to be displayed
  574.      * @see #showsRootHandles
  575.      * @beaninfo
  576.      *        bound: true
  577.      *  description: Whether the node handles are to be
  578.      *               displayed.
  579.      */
  580.     public void setShowsRootHandles(boolean newValue) {
  581.         boolean                oldValue = showsRootHandles;
  582.  
  583.         showsRootHandles = newValue;
  584.         firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue,
  585.                            showsRootHandles);
  586.         if (accessibleContext != null) {
  587.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  588.         }
  589.         invalidate();
  590.     }
  591.  
  592.     /**
  593.      * Returns true if handles for the root nodes are displayed.
  594.      * 
  595.      * @return true if root handles are displayed
  596.      * @see #showsRootHandles
  597.      */
  598.     public boolean getShowsRootHandles()
  599.     {
  600.         return showsRootHandles;
  601.     }
  602.  
  603.     /**
  604.      * Sets the height of each cell.  If the specified value
  605.      * is less than or equal to zero the current cell renderer is
  606.      * queried for each row's height.
  607.      *
  608.      * @param rowHeight the height of each cell, in pixels
  609.      * @beaninfo
  610.      *        bound: true
  611.      *  description: The height of each cell.
  612.      */
  613.     public void setRowHeight(int rowHeight)
  614.     {
  615.         int                oldValue = this.rowHeight;
  616.  
  617.         this.rowHeight = rowHeight;
  618.         firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, this.rowHeight);
  619.         invalidate();
  620.     }
  621.  
  622.     /**
  623.      * Returns the height of each row.  If the returned value is less than
  624.      * or equal to 0 the height for each row is determined by the
  625.      * renderer.
  626.      *
  627.      * @param the height of each cell, in pixels. Zero or negative if the
  628.      *        height of each row is determined by the tree cell renderer
  629.      */
  630.     public int getRowHeight()
  631.     {
  632.         return rowHeight;
  633.     }
  634.  
  635.     /**
  636.      * Returns true if the height of each display row is a fixed size.
  637.      *
  638.      * @return true if the height of each row is a fixed size
  639.      */
  640.     public boolean isFixedRowHeight()
  641.     {
  642.         return (rowHeight > 0);
  643.     }
  644.  
  645.     /**
  646.      * Specifies whether the UI should use a large model.
  647.      * (Not all UIs will implement this.) Fires a property change
  648.      * for the LARGE_MODEL_PROPERTY.
  649.      * 
  650.      * @param newValue true to suggest a large model to the UI
  651.      * @see #largeModel
  652.      * @beaninfo
  653.      *        bound: true
  654.      *  description: Whether the UI should use a 
  655.      *               large model.
  656.      */
  657.     public void setLargeModel(boolean newValue) {
  658.         boolean                oldValue = largeModel;
  659.  
  660.         largeModel = newValue;
  661.         firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, newValue);
  662.     }
  663.  
  664.     /**
  665.      * Returns true if the tree is configured for a large model.
  666.      * 
  667.      * @return true if a large model is suggested
  668.      * @see #largeModel
  669.      */
  670.     public boolean isLargeModel() {
  671.         return largeModel;
  672.     }
  673.  
  674.     /**
  675.      * Determines what happens when editing is interrupted by selecting
  676.      * another node in the tree, a change in the tree's data, or by some
  677.      * other means. Fires a property change for the 
  678.      * INVOKES_STOP_CELL_EDITING_PROPERTY.
  679.      *
  680.      * @param newValue true means that stopCellEditing is invoked when
  681.      *        editing is interruped, and data is saved. False means that
  682.      *        cancelCellEditing is invoked, and changes are lost.
  683.      * @beaninfo
  684.      *        bound: true
  685.      *  description: Determines what happens when editing is interrupted,
  686.      *               selecting another node in the tree, a change in the
  687.      *               tree's data, or some other means.
  688.      */
  689.     public void setInvokesStopCellEditing(boolean newValue) {
  690.         boolean                  oldValue = invokesStopCellEditing;
  691.  
  692.         invokesStopCellEditing = newValue;
  693.         firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, oldValue,
  694.                            newValue);
  695.     }
  696.  
  697.     /**
  698.      * Returns the indicator that tells what happens when editing is 
  699.      * interrupted.
  700.      *
  701.      * @return the indicator that tells what happens when editing is 
  702.      *         interrupted
  703.      * @see #setInvokesStopCellEditing
  704.      */
  705.     public boolean getInvokesStopCellEditing() {
  706.         return invokesStopCellEditing;
  707.     }
  708.  
  709.     /**
  710.      * Returns <code>isEditable</code>. This is invoked from the UI before
  711.      * editing begins to insure that the given path can be edited. This
  712.      * is provided as an entry point for subclassers to add filtered
  713.      * editing without having to resort to creating a new editor.
  714.      *
  715.      * @return true if every parent node and the node itself is editabled
  716.      * @see #isEditable
  717.      */
  718.     public boolean isPathEditable(TreePath path) {
  719.         return isEditable();
  720.     }
  721.  
  722.     /**
  723.      * Overrides JComponent's getToolTipText method in order to allow 
  724.      * renderer's tips to be used if it has text set.
  725.      * <p>
  726.      * NOTE: For JTree to properly display tooltips of its renderers
  727.      *       JTree must be a registered component with the ToolTipManager.
  728.      *       This can be done by invoking
  729.      *       <code>ToolTipManager.sharedInstance().registerComponent(tree)</code>.
  730.      *       This is not done automaticly!
  731.      *
  732.      * @param event the MouseEvent that initiated the ToolTip display
  733.      */
  734.     public String getToolTipText(MouseEvent event) {
  735.         if(event != null) {
  736.             Point p = event.getPoint();
  737.             int selRow = getRowForLocation(p.x, p.y);
  738.             TreeCellRenderer       r = getCellRenderer();
  739.  
  740.             if(selRow != -1 && r != null) {
  741.                 TreePath     path = getPathForRow(selRow);
  742.                 Object       lastPath = path.getLastPathComponent();
  743.                 Component    rComponent = r.getTreeCellRendererComponent
  744.                     (this, lastPath, isRowSelected(selRow),
  745.                      isExpanded(selRow), getModel().isLeaf(lastPath), selRow,
  746.                      true);
  747.  
  748.                 if(rComponent instanceof JComponent) {
  749.                     MouseEvent      newEvent;
  750.                     Rectangle       pathBounds = getPathBounds(path);
  751.  
  752.                     p.translate(-pathBounds.x, -pathBounds.y);
  753.                     newEvent = new MouseEvent(rComponent, event.getID(),
  754.                                           event.getWhen(),
  755.                                               event.getModifiers(),
  756.                                               p.x, p.y, event.getClickCount(),
  757.                                               event.isPopupTrigger());
  758.                     
  759.                     return ((JComponent)rComponent).getToolTipText(newEvent);
  760.                 }
  761.             }
  762.         }
  763.         return null;
  764.     }
  765.     
  766.     /**
  767.      * Called by the renderers to convert the specified value to
  768.      * text. This implementation returns value.toString(), ignoring
  769.      * all other arguments. To control the conversion, subclass this 
  770.      * method and use any of the arguments you need.
  771.      * 
  772.      * @param value the Object to convert to text
  773.      * @param selected true if the node is selected
  774.      * @param expanded true if the node is expanded
  775.      * @param leaf  true if the node is a leaf node
  776.      * @param row  an int specifying the node's display row, where 0 is 
  777.      *             the first row in the display
  778.      * @param hasFocus true if the node has the focus
  779.      * @return the String representation of the node's value
  780.      */
  781.     public String convertValueToText(Object value, boolean selected,
  782.                                      boolean expanded, boolean leaf, int row,
  783.                                      boolean hasFocus) {
  784.         if(value != null)
  785.             return value.toString();
  786.         return "";
  787.     }
  788.  
  789.     //
  790.     // The following are convenience methods that get forwarded to the
  791.     // current TreeUI.
  792.     //
  793.  
  794.     /**
  795.      * Returns the number of rows that are currently being displayed.
  796.      *
  797.      * @return the number of rows that are being displayed
  798.      */
  799.     public int getRowCount() {
  800.         TreeUI            tree = getUI();
  801.  
  802.         if(tree != null)
  803.             return tree.getRowCount();
  804.         return 0;
  805.     }
  806.  
  807.     /** 
  808.      * Selects the node identified by the specified path.  If any
  809.      * component of the path is hidden (under a collapsed node), it is 
  810.      * exposed (made viewable).
  811.      *
  812.      * @param path the TreePath specifying the node to select
  813.      */
  814.     public void setSelectionPath(TreePath path) {
  815.         getSelectionModel().setSelectionPath(path);
  816.         if (accessibleContext != null) {
  817.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  818.         }
  819.     }
  820.  
  821.     /** 
  822.      * Selects the nodes identified by the specified array of paths.
  823.      * If any component in any of the paths is hidden (under a collapsed
  824.      * node), it is exposed (made viewable).
  825.      *
  826.      * @param paths an array of TreePath objects that specifies the nodes
  827.      *        to select
  828.      */
  829.     public void setSelectionPaths(TreePath[] paths) {
  830.         getSelectionModel().setSelectionPaths(paths);
  831.         if (accessibleContext != null) {
  832.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  833.         }
  834.     }
  835.  
  836.     /**
  837.      * Selects the node at the specified row in the display.
  838.      *
  839.      * @param row  the row to select, where 0 is the first row in
  840.      *             the display
  841.      */
  842.     public void setSelectionRow(int row) {
  843.         int[]             rows = { row };
  844.  
  845.         setSelectionRows(rows);
  846.     }
  847.  
  848.     /**
  849.      * Selects the nodes corresponding to each of the specified rows
  850.      * in the display.
  851.      * 
  852.      * @param rows  an array of ints specifying the rows to select,
  853.      *              where 0 indicates the first row in the display
  854.      */
  855.     public void setSelectionRows(int[] rows) {
  856.         TreeUI               ui = getUI();
  857.  
  858.         if(ui != null && rows != null) {
  859.             int                  numRows = rows.length;
  860.             TreePath[]           paths = new TreePath[numRows];
  861.  
  862.             for(int counter = 0; counter < numRows; counter++)
  863.                 paths[counter] = ui.getPathForRow(rows[counter]);
  864.             setSelectionPaths(paths);
  865.         }
  866.     }
  867.  
  868.     /**
  869.      * Adds the node identified by the specified TreePath to the current
  870.      * selection. If any component of the path isn't visible, it is 
  871.      * made visible.
  872.      *
  873.      * @param path the TreePath to add
  874.      */
  875.     public void addSelectionPath(TreePath path) {
  876.         getSelectionModel().addSelectionPath(path);
  877.         if (accessibleContext != null) {
  878.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  879.         }
  880.     }
  881.  
  882.     /**
  883.      * Adds each path in the array of paths to the current selection.  If
  884.      * any component of any of the paths isn't visible, it is
  885.      * made visible.
  886.      *
  887.      * @param paths an array of TreePath objects that specifies the nodes
  888.      *              to add
  889.      */
  890.     public void addSelectionPaths(TreePath[] paths) {
  891.         getSelectionModel().addSelectionPaths(paths);
  892.         if (accessibleContext != null) {
  893.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  894.         }
  895.     }
  896.  
  897.     /**
  898.      * Adds the path at the specified row to the current selection.
  899.      *
  900.      * @param row  an int specifying the row of the node to add,
  901.      *             where 0 is the first row in the display
  902.      */
  903.     public void addSelectionRow(int row) {
  904.         int[]      rows = { row };
  905.  
  906.         addSelectionRows(rows);
  907.     }
  908.  
  909.     /**
  910.      * Adds the paths at each of the specified rows to the current selection.
  911.      * 
  912.      * @param rows  an array of ints specifying the rows to add,
  913.      *              where 0 indicates the first row in the display
  914.      */
  915.     public void addSelectionRows(int[] rows) {
  916.         TreeUI             ui = getUI();
  917.  
  918.         if(ui != null && rows != null) {
  919.             int                  numRows = rows.length;
  920.             TreePath[]           paths = new TreePath[numRows];
  921.  
  922.             for(int counter = 0; counter < numRows; counter++)
  923.                 paths[counter] = ui.getPathForRow(rows[counter]);
  924.             addSelectionPaths(paths);
  925.         }
  926.     }
  927.  
  928.     /**
  929.      * Returns the last path component in the first node of the current 
  930.      * selection.
  931.      *
  932.      * @return the last Object in the first selected node's TreePath,
  933.      *         or null if nothing is selected
  934.      * @see TreePath#getLastPathComponent
  935.      */
  936.     public Object getLastSelectedPathComponent() {
  937.         TreePath     selPath = getSelectionModel().getSelectionPath();
  938.  
  939.         if(selPath != null)
  940.             return selPath.getLastPathComponent();
  941.         return null;
  942.     }
  943.  
  944.     /**
  945.      * Returns the path to the first selected node.
  946.      *
  947.      * @return the TreePath for the first selected node, or null if
  948.      *         nothing is currently selected
  949.      */
  950.     public TreePath getSelectionPath() {
  951.         return getSelectionModel().getSelectionPath();
  952.     }
  953.  
  954.     /**
  955.      * Returns the paths of all selected values.
  956.      *
  957.      * @return an array of TreePath objects indicating the selected
  958.      *         nodes, or null if nothing is currently selected.
  959.      */
  960.     public TreePath[] getSelectionPaths() {
  961.         return getSelectionModel().getSelectionPaths();
  962.     }
  963.  
  964.     /**
  965.      * Returns all of the currently selected rows.
  966.      *
  967.      * @return an array of ints that identifies all currently selected rows
  968.      *         where 0 is the first row in the display
  969.      */
  970.     public int[] getSelectionRows() {
  971.         return getSelectionModel().getSelectionRows();
  972.     }
  973.  
  974.     /**
  975.      * Returns the number of nodes selected.
  976.      *
  977.      * @return the number of nodes selected
  978.      */
  979.     public int getSelectionCount() {
  980.         return selectionModel.getSelectionCount();
  981.     }
  982.  
  983.     /**
  984.      * Gets the first selected row.
  985.      *
  986.      * @return an int designating the first selected row, where 0 is the 
  987.      *         first row in the display
  988.      */
  989.     public int getMinSelectionRow() {
  990.         return getSelectionModel().getMinSelectionRow();
  991.     }
  992.  
  993.     /**
  994.      * Gets the last selected row.
  995.      *
  996.      * @return an int designating the last selected row, where 0 is the 
  997.      *         first row in the display
  998.      */
  999.     public int getMaxSelectionRow() {
  1000.         return getSelectionModel().getMaxSelectionRow();
  1001.     }
  1002.  
  1003.     /**
  1004.      * Returns the row index of the last node added to the selection.
  1005.      *
  1006.      * @return an int giving the row index of the last node added to the
  1007.      *         selection, where 0 is the first row in the display
  1008.      */
  1009.     public int getLeadSelectionRow() {
  1010.         return getSelectionModel().getLeadSelectionRow();
  1011.     }
  1012.  
  1013.     /**
  1014.      * Returns the path of the last node added to the selection.
  1015.      *
  1016.      * @return the TreePath of the last node added to the selection.
  1017.      */
  1018.     public TreePath getLeadSelectionPath() {
  1019.         return getSelectionModel().getLeadSelectionPath();
  1020.     }
  1021.  
  1022.     /**
  1023.      * Returns true if the item identified by the path is currently selected.
  1024.      *
  1025.      * @param path a TreePath identifying a node
  1026.      * @return true if the node is selected
  1027.      */
  1028.     public boolean isPathSelected(TreePath path) {
  1029.         return getSelectionModel().isPathSelected(path);
  1030.     }
  1031.  
  1032.     /**
  1033.      * Returns true if the node identitifed by row is selected.
  1034.      *
  1035.      * @param row  an int specifying a display row, where 0 is the first
  1036.      *             row in the display
  1037.      * @return true if the node is selected
  1038.      */
  1039.     public boolean isRowSelected(int row) {
  1040.         return getSelectionModel().isRowSelected(row);
  1041.     }
  1042.  
  1043.     /**
  1044.      * Returns true if the node identified by the path is currently expanded,
  1045.      * 
  1046.      * @param path  the TreePath specifying the node to check
  1047.      * @return false if any of the nodes in the node's path are collapsed, 
  1048.      *               true if all nodes in the path are expanded
  1049.      */
  1050.     public boolean isExpanded(TreePath path) {
  1051.         TreeUI                  tree = getUI();
  1052.  
  1053.         if(tree != null)
  1054.             return tree.isExpanded(path);
  1055.         return false;
  1056.     }
  1057.  
  1058.     /**
  1059.      * Returns true if the node at the specified display row is currently
  1060.      * expanded.
  1061.      * 
  1062.      * @param row  the row to check, where 0 is the first row in the 
  1063.      *             display
  1064.      * @return true if the node is currently expanded, otherwise false
  1065.      */
  1066.     public boolean isExpanded(int row) {
  1067.         TreeUI                  tree = getUI();
  1068.  
  1069.         if(tree != null)
  1070.             return tree.isExpanded(row);
  1071.         return false;
  1072.     }
  1073.  
  1074.     /**
  1075.      * Returns true if the value identified by path is currently collapsed,
  1076.      * this will return false if any of the values in path are currently
  1077.      * not being displayed.
  1078.      * 
  1079.      * @param path  the TreePath to check
  1080.      * @return true if any of the nodes in the node's path are collapsed, 
  1081.      *               false if all nodes in the path are expanded
  1082.      */
  1083.     public boolean isCollapsed(TreePath path) {
  1084.         TreeUI                  tree = getUI();
  1085.  
  1086.         if(tree != null)
  1087.             return tree.isCollapsed(path);
  1088.         return false;
  1089.     }
  1090.  
  1091.     /**
  1092.      * Returns true if the node at the specified display row is collapsed.
  1093.      * 
  1094.      * @param row  the row to check, where 0 is the first row in the 
  1095.      *             display
  1096.      * @return true if the node is currently collapsed, otherwise false
  1097.      */
  1098.     public boolean isCollapsed(int row) {
  1099.         TreeUI                  tree = getUI();
  1100.  
  1101.         if(tree != null)
  1102.             return tree.isCollapsed(row);
  1103.         return false;
  1104.     }
  1105.  
  1106.     /**
  1107.      * Ensures that the node identified by path is currently visible.
  1108.      *
  1109.      * @param path  the TreePath to make visible
  1110.      */
  1111.     public void makeVisible(TreePath path) {
  1112.         TreeUI                   tree = getUI();
  1113.  
  1114.         if(tree != null) {
  1115.             tree.makeVisible(path);
  1116.             if (accessibleContext != null) {
  1117.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1118.             }
  1119.         }
  1120.     }
  1121.  
  1122.     /**
  1123.      * Returns true if the value identified by path is currently visible,
  1124.      * false otherwise.
  1125.      *
  1126.      * @return true if the node is visible, otherwise false
  1127.      */
  1128.     public boolean isVisible(TreePath path) {
  1129.         TreeUI                   tree = getUI();
  1130.  
  1131.         if(tree != null)
  1132.             return tree.isVisible(path);
  1133.         return false;
  1134.     }
  1135.  
  1136.     /**
  1137.      * Returns the Rectangle that the specified node will be drawn
  1138.      * into. Returns null if any component in the path is hidden
  1139.      * (under a collapsed parent).
  1140.      * <p>
  1141.      * Note:<br>
  1142.      * This method returns a valid rectangle, even if the specified
  1143.      * node is not currently displayed.
  1144.      *
  1145.      * @param path the TreePath identifying the node
  1146.      * @return the Rectangle the node is drawn in, or null 
  1147.      */
  1148.     public Rectangle getPathBounds(TreePath path) {
  1149.         TreeUI                   tree = getUI();
  1150.  
  1151.         if(tree != null)
  1152.             return tree.getPathBounds(path);
  1153.         return null;
  1154.     }
  1155.  
  1156.     /**
  1157.      * Returns the Rectangle that the node at the specified row is
  1158.      * drawn in.
  1159.      *
  1160.      * @param row  the row to be drawn, where 0 is the first row in the 
  1161.      *             display
  1162.      * @return the Rectangle the node is drawn in 
  1163.      */
  1164.     public Rectangle getRowBounds(int row) {
  1165.         TreeUI                    tree = getUI();
  1166.  
  1167.         if(tree != null)
  1168.             return tree.getRowBounds(row);
  1169.         return null;
  1170.     }
  1171.  
  1172.     /**
  1173.      * Makes sure all the path components in path are expanded (except
  1174.      * for the last path component) and scrolls so that the 
  1175.      * node identified by the path is visible.
  1176.      * 
  1177.      * @param path  the TreePath identifying the node to bring into view
  1178.      */
  1179.     public void scrollPathToVisible(TreePath path) {
  1180.         TreeUI                 tree = getUI();
  1181.  
  1182.         if(tree != null) {
  1183.             tree.scrollPathToVisible(path);
  1184.             if (accessibleContext != null) {
  1185.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1186.             }
  1187.         }
  1188.     }
  1189.  
  1190.     /**
  1191.      * Scrolls the item identified by row to be visible. The minimum
  1192.      * of amount of scrolling necessary to bring the row into view
  1193.      * is performed. Only works when this JTree is contained in a
  1194.      * JSrollPane.
  1195.      *
  1196.      * @param row  an int specifying the row to scroll, where 0 is the
  1197.      *             first row in the display
  1198.      */
  1199.     public void scrollRowToVisible(int row) {
  1200.         TreeUI                  tree = getUI();
  1201.  
  1202.         if(tree != null) {
  1203.             tree.scrollRowToVisible(row);
  1204.             if (accessibleContext != null) {
  1205.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1206.             }
  1207.         }
  1208.     }
  1209.  
  1210.     /**
  1211.      * Returns the path for the specified row.
  1212.      * <!-->If row is not visible null is returned.<-->
  1213.      *
  1214.      * @param row  an int specifying a row
  1215.      * @return the TreePath to the specified node, null if
  1216.      *         row < 0 or row > getRowCount()
  1217.      */
  1218.     public TreePath getPathForRow(int row) {
  1219.         TreeUI                  tree = getUI();
  1220.  
  1221.         if(tree != null)
  1222.             return tree.getPathForRow(row);
  1223.         return null;
  1224.     }
  1225.  
  1226.     /**
  1227.      * Returns the row that displays the node identified by the specified
  1228.      * path. 
  1229.      * 
  1230.      * @param path  the TreePath identifying a node
  1231.      * @return an int specifying the display row, where 0 is the first
  1232.      *         row in the display, or -1 if any of the elements in path
  1233.      *         are hidden under a collapsed parent.
  1234.      */
  1235.     public int getRowForPath(TreePath path) {
  1236.         TreeUI                  tree = getUI();
  1237.  
  1238.         if(tree != null)
  1239.             return tree.getRowForPath(path);
  1240.         return -1;
  1241.     }
  1242.  
  1243.     /**
  1244.      * Ensures that the node identified by the specified path is 
  1245.      * expanded and visible.
  1246.      * 
  1247.      * @param path  the TreePath identifying a node
  1248.      */
  1249.     public void expandPath(TreePath path) {
  1250.         TreeUI                  tree = getUI();
  1251.  
  1252.         if(tree != null) {
  1253.             tree.expandPath(path);
  1254.             if (accessibleContext != null) {
  1255.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1256.             }
  1257.         }
  1258.     }
  1259.  
  1260.     /**
  1261.      * Ensures that the node in the specified row is expanded.
  1262.      *
  1263.      * @param row  an int specifying a display row, where 0 is the
  1264.      *             first row in the display
  1265.      */
  1266.     public void expandRow(int row) {
  1267.         TreeUI                  tree = getUI();
  1268.  
  1269.         if(tree != null) {
  1270.             tree.expandRow(row);
  1271.             if (accessibleContext != null) {
  1272.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1273.             }
  1274.         }
  1275.     }
  1276.  
  1277.     /**
  1278.      * Ensures that the node identified by the specified path is 
  1279.      * collapsed and visible.
  1280.      * 
  1281.      * @param path  the TreePath identifying a node
  1282.       */
  1283.     public void collapsePath(TreePath path) {
  1284.         TreeUI                  tree = getUI();
  1285.  
  1286.         if(tree != null) {
  1287.             tree.collapsePath(path);
  1288.             if (accessibleContext != null) {
  1289.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1290.             }
  1291.         }
  1292.     }
  1293.  
  1294.     /**
  1295.      * Ensures that the node in the specified row is collapsed.
  1296.      *
  1297.      * @param row  an int specifying a display row, where 0 is the
  1298.      *             first row in the display
  1299.       */
  1300.     public void collapseRow(int row) {
  1301.         TreeUI                  tree = getUI();
  1302.  
  1303.         if(tree != null) {
  1304.             tree.collapseRow(row);
  1305.             if (accessibleContext != null) {
  1306.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1307.             }
  1308.         }
  1309.     }
  1310.  
  1311.     /**
  1312.      * Returns the path for the node at the specified location.
  1313.      *
  1314.      * @param x an int giving the number of pixels horizontally from
  1315.      *          the left edge of the display area, minus any left margin
  1316.      * @param y an int giving the number of pixels vertically from
  1317.      *          the top of the display area, minus any top margin
  1318.      * @return  the TreePath for the node at that location
  1319.      */
  1320.     public TreePath getPathForLocation(int x, int y) {
  1321.         TreePath          closestPath = getClosestPathForLocation(x, y);
  1322.  
  1323.         if(closestPath != null) {
  1324.             Rectangle       pathBounds = getPathBounds(closestPath);
  1325.  
  1326.             if(x >= pathBounds.x && x < (pathBounds.x + pathBounds.width) &&
  1327.                y >= pathBounds.y && y < (pathBounds.y + pathBounds.height))
  1328.                 return closestPath;
  1329.         }
  1330.         return null;
  1331.     }
  1332.  
  1333.     /**
  1334.      * Returns the row for the specified location. 
  1335.      *
  1336.      * @param x an int giving the number of pixels horizontally from
  1337.      *          the left edge of the display area, minus any left margin
  1338.      * @param y an int giving the number of pixels vertically from
  1339.      *          the top of the display area, minus any top margin
  1340.      * @return the row corresponding to the location, or -1 if the
  1341.      *         location is not within the bounds of a displayed cell
  1342.      * @see #getClosestRowForLocation
  1343.      */
  1344.     public int getRowForLocation(int x, int y) {
  1345.         int             closestRow = getClosestRowForLocation(x, y);
  1346.  
  1347.         if(closestRow != -1) {
  1348.             Rectangle       rowBounds = getRowBounds(closestRow);
  1349.  
  1350.             if(x >= rowBounds.x && x < (rowBounds.x + rowBounds.width) &&
  1351.                y >= rowBounds.y && y < (rowBounds.y + rowBounds.height))
  1352.                 return closestRow;
  1353.         }
  1354.         return -1;
  1355.     }
  1356.  
  1357.     /**
  1358.      * Returns the path to the node that is closest to x,y.  If
  1359.      * nothing is currently visible, or there is no model, returns
  1360.      * null, otherwise it always returns a valid path.  To test if
  1361.      * the node is exactly at x, y, get the node's bounds and
  1362.      * test x, y against that.
  1363.      *
  1364.      * @param x an int giving the number of pixels horizontally from
  1365.      *          the left edge of the display area, minus any left margin
  1366.      * @param y an int giving the number of pixels vertically from
  1367.      *          the top of the display area, minus any top margin
  1368.      * @return  the TreePath for the node closest to that location,
  1369.      *          null if nothing is visible or there is no model
  1370.      *
  1371.      * @see #getPathForLocation
  1372.      * @see #getPathBounds
  1373.      */
  1374.     public TreePath getClosestPathForLocation(int x, int y) {
  1375.         TreeUI                  tree = getUI();
  1376.  
  1377.         if(tree != null)
  1378.             return tree.getClosestPathForLocation(x, y);
  1379.         return null;
  1380.     }
  1381.  
  1382.     /**
  1383.      * Returns the row to the node that is closest to x,y.  If
  1384.      * nothing is visible or there is no model, returns -1. Otherwise,
  1385.      * it always returns a valid row.  To test if the returned object is 
  1386.      * exactly at x, y, get the bounds for the node at the returned
  1387.      * row and test x, y against that.
  1388.      *
  1389.      * @param x an int giving the number of pixels horizontally from
  1390.      *          the left edge of the display area, minus any left margin
  1391.      * @param y an int giving the number of pixels vertically from
  1392.      *          the top of the display area, minus any top margin
  1393.      * @return the row closest to the location, -1 if nothing is
  1394.      *         visible or there is no model
  1395.      *
  1396.      * @see #getRowForLocation
  1397.      * @see #getRowBounds
  1398.      */
  1399.     public int getClosestRowForLocation(int x, int y) {
  1400.         TreeUI                  tree = getUI();
  1401.  
  1402.         if(tree != null)
  1403.             return tree.getClosestRowForLocation(x, y);
  1404.         return -1;
  1405.     }
  1406.  
  1407.     /**
  1408.      * Returns true if the tree is being edited.  The item that is being
  1409.      * edited can be obtained using <code>getSelectionPath</code>.
  1410.      *
  1411.      * @return true if the user is currently editing a node
  1412.      * @see #getSelectionPath
  1413.      */
  1414.     public boolean isEditing() {
  1415.         TreeUI                  tree = getUI();
  1416.  
  1417.         if(tree != null)
  1418.             return tree.isEditing();
  1419.         return false;
  1420.     }
  1421.  
  1422.     /**
  1423.      * Stops the current editing session.  Has no effect if the
  1424.      * tree isn't being edited.
  1425.      *
  1426.      * @return true if editing was in progress and is now stopped,
  1427.      *              false if editing was not in progress
  1428.      */
  1429.     public boolean stopEditing() {
  1430.         TreeUI                  tree = getUI();
  1431.  
  1432.         if(tree != null)
  1433.             return tree.stopEditing();
  1434.         return false;
  1435.     }
  1436.  
  1437.     /**
  1438.      * Selects the node identified by the specified path and initiates
  1439.      * editing.  The edit-attempt fails if the CellEditor does not allow
  1440.      * editing for the specified item.
  1441.      * 
  1442.      * @param path  the TreePath identifying a node
  1443.      */
  1444.     public void startEditingAtPath(TreePath path) {
  1445.         TreeUI                  tree = getUI();
  1446.  
  1447.         if(tree != null)
  1448.             tree.startEditingAtPath(path);
  1449.     }
  1450.  
  1451.     /**
  1452.      * Returns the path to the element that is currently being edited.
  1453.      *
  1454.      * @return  the TreePath for the node being edited
  1455.      */
  1456.     public TreePath getEditingPath() {
  1457.         TreeUI                  tree = getUI();
  1458.  
  1459.         if(tree != null)
  1460.             return tree.getEditingPath();
  1461.         return null;
  1462.     }
  1463.  
  1464.     //
  1465.     // Following are primarily convenience methods for mapping from
  1466.     // row based selections to path selections.  Sometimes it is
  1467.     // easier to deal with these than paths (mouse downs, key downs
  1468.     // usually just deal with index based selections).
  1469.     // Since row based selections require a UI many of these won't work
  1470.     // without one.
  1471.     //
  1472.  
  1473.     /**
  1474.      * Sets the tree's selection model. When a null value is specified
  1475.      * an empty electionModel is used, which does not allow selections.
  1476.      *
  1477.      * @param selectionModel the TreeSelectionModel to use, or null to
  1478.      *        disable selections
  1479.      * @see TreeSelectionModel
  1480.      * @beaninfo
  1481.      *        bound: true
  1482.      *  description: The tree's selection model.
  1483.      */
  1484.     public void setSelectionModel(TreeSelectionModel selectionModel) {
  1485.         if(selectionModel == null)
  1486.             selectionModel = EmptySelectionModel.sharedInstance();
  1487.  
  1488.         TreeSelectionModel         oldValue = this.selectionModel;
  1489.  
  1490.         this.selectionModel = selectionModel;
  1491.         firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue,
  1492.                            this.selectionModel);
  1493.         if (accessibleContext != null) {
  1494.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1495.         }
  1496.     }
  1497.  
  1498.     /**
  1499.      * Returns the model for selections. This should always return a 
  1500.      * non-null value. If you don't want to allow anything to be selected
  1501.      * set the selection model to null, which forces an empty
  1502.      * selection model to be used.
  1503.      *
  1504.      * @param the TreeSelectionModel in use
  1505.      * @see #setSelectionModel
  1506.      */
  1507.     public TreeSelectionModel getSelectionModel() {
  1508.         return selectionModel;
  1509.     }
  1510.  
  1511.     /**
  1512.      * Returns JTreePath instances representing the path between index0
  1513.      * and index1 (including index1).  Returns null if there is no tree.
  1514.      *
  1515.      * @param index0  an int specifying a display row, where 0 is the
  1516.      *                first row in the display
  1517.      * @param index0  an int specifying a second display row
  1518.      * @return an array of TreePath objects, one for each node between
  1519.      *         index0 and index1, inclusive
  1520.      */
  1521.     protected TreePath[] getPathBetweenRows(int index0, int index1) {
  1522.         int              newMinIndex, newMaxIndex;
  1523.         TreeUI           tree = getUI();
  1524.  
  1525.         newMinIndex = Math.min(index0, index1);
  1526.         newMaxIndex = Math.max(index0, index1);
  1527.  
  1528.         if(tree != null) {
  1529.             TreePath[]            selection = new TreePath[newMaxIndex -
  1530.                                                             newMinIndex + 1];
  1531.  
  1532.             for(int counter = newMinIndex; counter <= newMaxIndex; counter++)
  1533.                 selection[counter - newMinIndex] = tree.getPathForRow(counter);
  1534.             return selection;
  1535.         }
  1536.         return null;
  1537.     }
  1538.  
  1539.     /**
  1540.      * Selects the nodes between index0 and index1, inclusive.
  1541.      *
  1542.      * @param index0  an int specifying a display row, where 0 is the
  1543.      *                first row in the display
  1544.      * @param index0  an int specifying a second display row
  1545.     */
  1546.     public void setSelectionInterval(int index0, int index1) {
  1547.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1548.  
  1549.         this.getSelectionModel().setSelectionPaths(paths);
  1550.         if (accessibleContext != null) {
  1551.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1552.         }
  1553.     }
  1554.  
  1555.     /**
  1556.      * Adds the paths between index0 and index1, inclusive, to the 
  1557.      * selection.
  1558.      *
  1559.      * @param index0  an int specifying a display row, where 0 is the
  1560.      *                first row in the display
  1561.      * @param index0  an int specifying a second display row
  1562.      */
  1563.     public void addSelectionInterval(int index0, int index1) {
  1564.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1565.  
  1566.         this.getSelectionModel().addSelectionPaths(paths);
  1567.         if (accessibleContext != null) {
  1568.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1569.         }
  1570.     }
  1571.  
  1572.     /**
  1573.      * Removes the nodes between index0 and index1, inclusive, from the 
  1574.      * selection.
  1575.      *
  1576.      * @param index0  an int specifying a display row, where 0 is the
  1577.      *                first row in the display
  1578.      * @param index0  an int specifying a second display row
  1579.      */
  1580.     public void removeSelectionInterval(int index0, int index1) {
  1581.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1582.  
  1583.         this.getSelectionModel().removeSelectionPaths(paths);
  1584.         if (accessibleContext != null) {
  1585.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1586.         }
  1587.     }
  1588.  
  1589.     /**
  1590.      * Removes the node identified by the specified path from the current
  1591.      * selection.
  1592.      * 
  1593.      * @param path  the TreePath identifying a node
  1594.      */
  1595.     public void removeSelectionPath(TreePath path) {
  1596.         this.getSelectionModel().removeSelectionPath(path);
  1597.         if (accessibleContext != null) {
  1598.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1599.         }
  1600.     }
  1601.  
  1602.     /**
  1603.      * Removes the nodes identified by the specified paths from the 
  1604.      * current selection.
  1605.      *
  1606.      * @param paths an array of TreePath objects that specifies the nodes
  1607.      *              to remove
  1608.      */
  1609.     public void removeSelectionPaths(TreePath[] paths) {
  1610.         this.getSelectionModel().removeSelectionPaths(paths);
  1611.         if (accessibleContext != null) {
  1612.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1613.         }
  1614.     }
  1615.  
  1616.     /**
  1617.      * Removes the path at the index <code>row</code> from the current
  1618.      * selection.
  1619.      * 
  1620.      * @param path  the TreePath identifying the node to remove
  1621.      */
  1622.     public void removeSelectionRow(int row) {
  1623.         int[]             rows = { row };
  1624.  
  1625.         removeSelectionRows(rows);
  1626.     }
  1627.  
  1628.     /**
  1629.      * Removes the paths that are selected at each of the specified
  1630.      * rows.
  1631.      *
  1632.      * @param row  an array of ints specifying display rows, where 0 is 
  1633.      *             the first row in the display
  1634.      */
  1635.     public void removeSelectionRows(int[] rows) {
  1636.         TreeUI             ui = getUI();
  1637.  
  1638.         if(ui != null && rows != null) {
  1639.             int                  numRows = rows.length;
  1640.             TreePath[]           paths = new TreePath[numRows];
  1641.  
  1642.             for(int counter = 0; counter < numRows; counter++)
  1643.                 paths[counter] = ui.getPathForRow(rows[counter]);
  1644.             removeSelectionPaths(paths);
  1645.         }
  1646.     }
  1647.  
  1648.     /**
  1649.      * Clears the selection.
  1650.      */
  1651.     public void clearSelection() {
  1652.         getSelectionModel().clearSelection();
  1653.         if (accessibleContext != null) {
  1654.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1655.         }
  1656.     }
  1657.  
  1658.     /**
  1659.      * Returns true if the selection is currently empty.
  1660.      *
  1661.      * @return true if the selection is currently empty
  1662.      */
  1663.     public boolean isSelectionEmpty() {
  1664.         return getSelectionModel().isSelectionEmpty();
  1665.     }
  1666.  
  1667.     /**
  1668.      * Adds a listener for TreeExpansion events.
  1669.      *
  1670.      * @param tel a TreeExpansionListener that will be notified when
  1671.      *            a tree node is expanded or collapsed (a "negative
  1672.      *            expansion")
  1673.      */
  1674.     public void addTreeExpansionListener(TreeExpansionListener tel) {
  1675.         listenerList.add(TreeExpansionListener.class, tel);
  1676.     }
  1677.  
  1678.     /**
  1679.      * Removes a listener for TreeExpansion events.
  1680.      *
  1681.      * @param tel the TreeExpansionListener to remove
  1682.      */
  1683.     public void removeTreeExpansionListener(TreeExpansionListener tel) {
  1684.         listenerList.remove(TreeExpansionListener.class, tel);
  1685.     }
  1686.  
  1687.     /**
  1688.      * Notify all listeners that have registered interest for
  1689.      * notification on this event type.  The event instance 
  1690.      * is lazily created using the parameters passed into 
  1691.      * the fire method.
  1692.      *
  1693.      * @param path the TreePath indicating the node that was expanded
  1694.      * @see EventListenerList
  1695.      */
  1696.      public void fireTreeExpanded(TreePath path) {
  1697.         // Guaranteed to return a non-null array
  1698.         Object[] listeners = listenerList.getListenerList();
  1699.         TreeExpansionEvent e = null;
  1700.         // Process the listeners last to first, notifying
  1701.         // those that are interested in this event
  1702.         for (int i = listeners.length-2; i>=0; i-=2) {
  1703.             if (listeners[i]==TreeExpansionListener.class) {
  1704.                 // Lazily create the event:
  1705.                 if (e == null)
  1706.                     e = new TreeExpansionEvent(this, path);
  1707.                 ((TreeExpansionListener)listeners[i+1]).
  1708.                     treeExpanded(e);
  1709.             }          
  1710.         }
  1711.     }   
  1712.  
  1713.     /**
  1714.      * Notify all listeners that have registered interest for
  1715.      * notification on this event type.  The event instance 
  1716.      * is lazily created using the parameters passed into 
  1717.      * the fire method.
  1718.      *
  1719.      * @param path the TreePath indicating the node that was collapsed
  1720.      * @see EventListenerList
  1721.      */
  1722.     public void fireTreeCollapsed(TreePath path) {
  1723.         // Guaranteed to return a non-null array
  1724.         Object[] listeners = listenerList.getListenerList();
  1725.         TreeExpansionEvent e = null;
  1726.         // Process the listeners last to first, notifying
  1727.         // those that are interested in this event
  1728.         for (int i = listeners.length-2; i>=0; i-=2) {
  1729.             if (listeners[i]==TreeExpansionListener.class) {
  1730.                 // Lazily create the event:
  1731.                 if (e == null)
  1732.                     e = new TreeExpansionEvent(this, path);
  1733.                 ((TreeExpansionListener)listeners[i+1]).
  1734.                     treeCollapsed(e);
  1735.             }          
  1736.         }
  1737.     }   
  1738.  
  1739.     /**
  1740.      * Adds a listener for TreeSelection events.
  1741.      *
  1742.      * @param tsl the TreeSelectionListener that will be notified when
  1743.      *            a node is selected or deselected (a "negative
  1744.      *            selection")
  1745.      */
  1746.     public void addTreeSelectionListener(TreeSelectionListener tsl) {
  1747.         listenerList.add(TreeSelectionListener.class,tsl);
  1748.         if(listenerList.getListenerCount(TreeSelectionListener.class) != 0
  1749.            && selectionRedirector == null) {
  1750.             selectionRedirector = new TreeSelectionRedirector();
  1751.             selectionModel.addTreeSelectionListener(selectionRedirector);
  1752.         }
  1753.     }
  1754.  
  1755.     /**
  1756.      * Removes a TreeSelection listener.
  1757.      *
  1758.      * @param tsl the TreeSelectionListener to remove
  1759.      */
  1760.     public void removeTreeSelectionListener(TreeSelectionListener tsl) {
  1761.         listenerList.remove(TreeSelectionListener.class,tsl);
  1762.         if(listenerList.getListenerCount(TreeSelectionListener.class) == 0
  1763.            && selectionRedirector != null) {
  1764.             selectionModel.removeTreeSelectionListener
  1765.                 (selectionRedirector);
  1766.             selectionRedirector = null;
  1767.         }
  1768.     }
  1769.  
  1770.     /**
  1771.      * Notify all listeners that have registered interest for
  1772.      * notification on this event type.  The event instance 
  1773.      * is lazily created using the parameters passed into 
  1774.      * the fire method.
  1775.      *
  1776.      * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  1777.      *          when a node is selected or deselected
  1778.      * @see EventListenerList
  1779.      */
  1780.     protected void fireValueChanged(TreeSelectionEvent e) {
  1781.         // Guaranteed to return a non-null array
  1782.         Object[] listeners = listenerList.getListenerList();
  1783.         // Process the listeners last to first, notifying
  1784.         // those that are interested in this event
  1785.         for (int i = listeners.length-2; i>=0; i-=2) {
  1786.             // TreeSelectionEvent e = null;
  1787.             if (listeners[i]==TreeSelectionListener.class) {
  1788.                 // Lazily create the event:
  1789.                 // if (e == null)
  1790.                 // e = new ListSelectionEvent(this, firstIndex, lastIndex);
  1791.                 ((TreeSelectionListener)listeners[i+1]).valueChanged(e);
  1792.             }          
  1793.         }
  1794.     }
  1795.  
  1796.     /**
  1797.      * Sent when the tree has changed enough that we need to resize
  1798.      * the bounds, but not enough that we need to remove the
  1799.      * expanded node set (e.g nodes were expanded or collapsed, or
  1800.      * nodes were inserted into the tree)
  1801.      */
  1802.     public void treeDidChange() {
  1803.         revalidate();
  1804.         repaint();
  1805.     }
  1806.  
  1807.     /**
  1808.      * Sets the number of rows that are to be visible.
  1809.      * This will only work if the reciever is contained in a JScrollPane,
  1810.      * and will adjust the preferred size and size of that scrollpane.
  1811.      *
  1812.      * @param newCount the number of rows to display
  1813.      * @beaninfo
  1814.      *        bound: true
  1815.      *  description: The number of rows that are to be visible.
  1816.      */
  1817.     public void setVisibleRowCount(int newCount) {
  1818.         int                 oldCount = visibleRowCount;
  1819.  
  1820.         visibleRowCount = newCount;
  1821.         firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldCount,
  1822.                            visibleRowCount);
  1823.         invalidate();
  1824.         if (accessibleContext != null) {
  1825.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1826.         }
  1827.     }
  1828.  
  1829.     /**
  1830.      * Returns the number of rows that are visible in the display area.
  1831.      *
  1832.      * @return the number of rows displayed
  1833.      */
  1834.     public int getVisibleRowCount() {
  1835.         return visibleRowCount;
  1836.     }
  1837.  
  1838.     // Serialization support.  
  1839.     private void writeObject(ObjectOutputStream s) throws IOException {
  1840.         Vector      values = new Vector();
  1841.  
  1842.         s.defaultWriteObject();
  1843.         // Save the cellRenderer, if its Serializable.
  1844.         if(cellRenderer != null && cellRenderer instanceof Serializable) {
  1845.             values.addElement("cellRenderer");
  1846.             values.addElement(cellRenderer);
  1847.         }
  1848.         // Save the cellEditor, if its Serializable.
  1849.         if(cellEditor != null && cellEditor instanceof Serializable) {
  1850.             values.addElement("cellEditor");
  1851.             values.addElement(cellEditor);
  1852.         }
  1853.         // Save the treeModel, if its Serializable.
  1854.         if(treeModel != null && treeModel instanceof Serializable) {
  1855.             values.addElement("treeModel");
  1856.             values.addElement(treeModel);
  1857.         }
  1858.         // Save the selectionModel, if its Serializable.
  1859.         if(selectionModel != null && selectionModel instanceof Serializable) {
  1860.             values.addElement("selectionModel");
  1861.             values.addElement(selectionModel);
  1862.         }
  1863.         s.writeObject(values);
  1864.     }
  1865.  
  1866.     private void readObject(ObjectInputStream s) 
  1867.         throws IOException, ClassNotFoundException {
  1868.         s.defaultReadObject();
  1869.  
  1870.         Vector          values = (Vector)s.readObject();
  1871.         int             indexCounter = 0;
  1872.         int             maxCounter = values.size();
  1873.  
  1874.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1875.            equals("cellRenderer")) {
  1876.             cellRenderer = (TreeCellRenderer)values.elementAt(++indexCounter);
  1877.             indexCounter++;
  1878.         }
  1879.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1880.            equals("cellEditor")) {
  1881.             cellEditor = (TreeCellEditor)values.elementAt(++indexCounter);
  1882.             indexCounter++;
  1883.         }
  1884.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1885.            equals("treeModel")) {
  1886.             treeModel = (TreeModel)values.elementAt(++indexCounter);
  1887.             indexCounter++;
  1888.         }
  1889.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1890.            equals("selectionModel")) {
  1891.             selectionModel = (TreeSelectionModel)values.elementAt(++indexCounter);
  1892.             indexCounter++;
  1893.         }
  1894.     }
  1895.  
  1896.     /**
  1897.      * EmptySelectionModel is a TreeSelectionModel that does not allow
  1898.      * anything to be selected.
  1899.      * <p>
  1900.      * Warning: serialized objects of this class will not be compatible with
  1901.      * future swing releases.  The current serialization support is appropriate
  1902.      * for short term storage or RMI between Swing1.0 applications.  It will
  1903.      * not be possible to load serialized Swing1.0 objects with future releases
  1904.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1905.      * baseline for the serialized form of Swing objects.
  1906.      */
  1907.     protected static class EmptySelectionModel extends
  1908.               DefaultTreeSelectionModel
  1909.     {
  1910.         /** Unique shared instance. */
  1911.         protected static final EmptySelectionModel sharedInstance =
  1912.             new EmptySelectionModel();
  1913.  
  1914.         /** Returns a shared instance of an empty selection model */
  1915.         static public EmptySelectionModel sharedInstance() {
  1916.             return sharedInstance;
  1917.         }
  1918.  
  1919.         /** A null implementation that selects nothing */
  1920.         public void setSelectionPaths(TreePath[] pPaths) {}
  1921.         /** A null implementation that adds nothing */
  1922.         public void addSelectionPaths(TreePath[] paths) {}
  1923.         /** A null implementation that removes nothing */
  1924.         public void removeSelectionPaths(TreePath[] paths) {}
  1925.     }
  1926.  
  1927.  
  1928.     /**
  1929.      * Handles creating a new TreeSelectionEvent with the JTree as the
  1930.      * source and passing it off to all the listeners.
  1931.      * <p>
  1932.      * Warning: serialized objects of this class will not be compatible with
  1933.      * future swing releases.  The current serialization support is appropriate
  1934.      * for short term storage or RMI between Swing1.0 applications.  It will
  1935.      * not be possible to load serialized Swing1.0 objects with future releases
  1936.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1937.      * baseline for the serialized form of Swing objects.
  1938.      */
  1939.     protected class TreeSelectionRedirector implements Serializable,
  1940.                     TreeSelectionListener
  1941.     {
  1942.         /**
  1943.          * Invoked by the TreeSelectionModel when the selection changes.
  1944.          * 
  1945.          * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  1946.          */
  1947.         public void valueChanged(TreeSelectionEvent e) {
  1948.             TreeSelectionEvent       newE;
  1949.  
  1950.             newE = (TreeSelectionEvent)e.cloneWithSource(JTree.this);
  1951.             fireValueChanged(newE);
  1952.         }
  1953.     } // End of class JTree.TreeSelectionRedirector
  1954.  
  1955.     /**
  1956.      * Returns true to indicate that this component paints every pixel
  1957.      * in its range. (In other words, it does not have a transparent
  1958.      * background or foreground.)
  1959.      *
  1960.      * @return true
  1961.      * @see JComponent#isOpaque
  1962.      */
  1963.     public boolean isOpaque() {
  1964.         return true;
  1965.     }
  1966.  
  1967.     //
  1968.     // Scrollable interface
  1969.     //
  1970.  
  1971.     /**
  1972.      * Returns the preferred viewable size of a JTree. The height is
  1973.      * determined from <code>getVisibleRowCount</code> and the width
  1974.      * is the current preferred width.
  1975.      *
  1976.      * @return a Dimension object containing the preferred size
  1977.      */
  1978.     public Dimension getPreferredScrollableViewportSize() {
  1979.         int                 width = getPreferredSize().width;
  1980.         int                 visRows = getVisibleRowCount();
  1981.         int                 height;
  1982.  
  1983.         if(isFixedRowHeight())
  1984.             height = visRows * getRowHeight();
  1985.         else {
  1986.             TreeUI          ui = getUI();
  1987.  
  1988.             if(ui != null && ui.getRowCount() > 0)
  1989.                 height = getRowBounds(0).height * visRows;
  1990.             else
  1991.                 height = 16 * visRows;
  1992.         }
  1993.         return new Dimension(width, height);
  1994.     }
  1995.  
  1996.     /**
  1997.      * Returns the amount to increment when scrolling. The amount is
  1998.      * the height of the first visible row that isn't completely in view
  1999.      * or, if it is totally visible, the height of the next row in the
  2000.      * scrolling direction.
  2001.      * 
  2002.      * @param visibleRect The view area visible within the viewport
  2003.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2004.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2005.      * @return The "unit" increment for scrolling in the specified direction
  2006.      * @see JScrollBar#setUnitIncrement
  2007.      */
  2008.     public int getScrollableUnitIncrement(Rectangle visibleRect,
  2009.                                           int orientation, int direction) {
  2010.         if(orientation == SwingConstants.VERTICAL) {
  2011.             Rectangle       rowBounds;
  2012.             int             firstIndex = getClosestRowForLocation
  2013.                                          (0, visibleRect.y);
  2014.  
  2015.             if(firstIndex != -1) {
  2016.                 rowBounds = getRowBounds(firstIndex);
  2017.                 if(rowBounds.y != visibleRect.y) {
  2018.                     if(direction < 0) // UP
  2019.                         return (visibleRect.y - rowBounds.y);
  2020.                     return (rowBounds.y + rowBounds.height - visibleRect.y);
  2021.                 }
  2022.                 if(direction < 0) { // UP
  2023.                     if(firstIndex != 0) {
  2024.                         rowBounds = getRowBounds(firstIndex - 1);
  2025.                         return rowBounds.height;
  2026.                     }
  2027.                 }
  2028.                 else {
  2029.                     return rowBounds.height;
  2030.                 }
  2031.             }
  2032.             return 0;
  2033.         }
  2034.         return 4;
  2035.     }
  2036.  
  2037.  
  2038.     /**
  2039.      * Returns the amount for a block inrecment, which is the height or
  2040.      * width of <code>visibleRect</code>, based on <code>orientation</code>.
  2041.      * 
  2042.      * @param visibleRect The view area visible within the viewport
  2043.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2044.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2045.      * @return The "block" increment for scrolling in the specified direction.
  2046.      * @see JScrollBar#setBlockIncrement
  2047.      */
  2048.     public int getScrollableBlockIncrement(Rectangle visibleRect,
  2049.                                            int orientation, int direction) {
  2050.         return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
  2051.             visibleRect.width;
  2052.     }
  2053.     
  2054.  
  2055.     /**
  2056.      * Returns false to indicate that the width of the viewport does not 
  2057.      * determine the width of the table.
  2058.      * 
  2059.      * @return false
  2060.      * @see Scrollable#getScrollableTracksViewportWidth
  2061.      */
  2062.     public boolean getScrollableTracksViewportWidth() {
  2063.         return false;
  2064.     }
  2065.  
  2066.     /**
  2067.      * Returns false to indicate that the height of the viewport does not 
  2068.      * determine the height of the table.
  2069.      * 
  2070.      * @return false
  2071.      * @see Scrollable#getScrollableTracksViewportHeight
  2072.      */
  2073.     public boolean getScrollableTracksViewportHeight() {
  2074.         return false;
  2075.     }
  2076.  
  2077.     /**
  2078.      * DynamicUtilTreeNode can wrap vectors/hashtables/arrays/strings and
  2079.      * create the appropriate children tree nodes as necessary. It is
  2080.      * dynamic in that it'll only create the children as necessary.
  2081.      * <p>
  2082.      * Warning: serialized objects of this class will not be compatible with
  2083.      * future swing releases.  The current serialization support is appropriate
  2084.      * for short term storage or RMI between Swing1.0 applications.  It will
  2085.      * not be possible to load serialized Swing1.0 objects with future releases
  2086.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  2087.      * baseline for the serialized form of Swing objects.
  2088.      */
  2089.     public static class DynamicUtilTreeNode extends DefaultMutableTreeNode {
  2090.         /* Does the receiver have children? */
  2091.         protected boolean            hasChildren;
  2092.         /** Value to create children with. */
  2093.         protected Object             childValue;
  2094.         /* Have the children been loaded yet? */
  2095.         protected boolean            loadedChildren;
  2096.  
  2097.         /**
  2098.          * Adds to parent all the children in <code>children</code>.
  2099.          * If <code>children</code> is an array or Vector all of its
  2100.          * elements are added is children, otherwise if <code>children</code>
  2101.          * is a Hashtable all the key/value pairs are added in the order
  2102.          * Enumeration returns them.
  2103.          */
  2104.         public static void createChildren(DefaultMutableTreeNode parent,
  2105.                                           Object children) {
  2106.             if(children instanceof Vector) {
  2107.                 Vector          childVector = (Vector)children;
  2108.  
  2109.                 for(int counter = 0, maxCounter = childVector.size();
  2110.                     counter < maxCounter; counter++)
  2111.                     parent.add(new DynamicUtilTreeNode
  2112.                                (childVector.elementAt(counter),
  2113.                                 childVector.elementAt(counter)));
  2114.             }
  2115.             else if(children instanceof Hashtable) {
  2116.                 Hashtable           childHT = (Hashtable)children;
  2117.                 Enumeration         keys = childHT.keys();
  2118.                 Object              aKey;
  2119.  
  2120.                 while(keys.hasMoreElements()) {
  2121.                     aKey = keys.nextElement();
  2122.                     parent.add(new DynamicUtilTreeNode(aKey,
  2123.                                                        childHT.get(aKey)));
  2124.                 }
  2125.             }
  2126.             else if(children instanceof Object[]) {
  2127.                 Object[]             childArray = (Object[])children;
  2128.  
  2129.                 for(int counter = 0, maxCounter = childArray.length;
  2130.                     counter < maxCounter; counter++)
  2131.                     parent.add(new DynamicUtilTreeNode(childArray[counter],
  2132.                                                        childArray[counter]));
  2133.             }
  2134.         }
  2135.  
  2136.         /**
  2137.          * Creates a node with the specified object as its value and
  2138.          * with the specified children. For the node to allow children,
  2139.          * the children-object must be an array of objects, a Vector,
  2140.          * or a Hashtable -- even if empty. Otherwise, the node is not
  2141.          * allowed to have children.
  2142.          *
  2143.          * @param value  the Object that is the value for the new node
  2144.          * @param children an array of Objects, a Vector, or a Hashtable
  2145.          *                 used to create the child nodes. If any other
  2146.          *                 object is specified, or if the value is null,
  2147.          *                 then the node is not allowed to have children.
  2148.          */
  2149.         public DynamicUtilTreeNode(Object value, Object children) {
  2150.             super(value);
  2151.             loadedChildren = false;
  2152.             childValue = children;
  2153.             if(children != null) {
  2154.                 if(children instanceof Vector)
  2155.                     setAllowsChildren(true);
  2156.                 else if(children instanceof Hashtable)
  2157.                     setAllowsChildren(true);
  2158.                 else if(children instanceof Object[])
  2159.                     setAllowsChildren(true);
  2160.                 else
  2161.                     setAllowsChildren(false);
  2162.             }
  2163.             else
  2164.                 setAllowsChildren(false);
  2165.         }
  2166.  
  2167.         /**
  2168.          * Returns true if this node allows children. Whether the node
  2169.          * allows children depends on how it was created.
  2170.          *
  2171.          * @return true if this node allows children, false otherwise.
  2172.          * @see JTree.DynamicUtilTreeNode#DynamicUtilTreeNode(Object, Object)
  2173.          */
  2174.         public boolean isLeaf() {
  2175.             return !getAllowsChildren();
  2176.         }
  2177.  
  2178.         /**
  2179.          * Returns the number of child nodes.
  2180.          *
  2181.          * @return the number of child nodes
  2182.          */
  2183.         public int getChildCount() {
  2184.             if(!loadedChildren)
  2185.                 loadChildren();
  2186.             return super.getChildCount();
  2187.         }
  2188.  
  2189.         /**
  2190.          * Loads the children based on childValue. If childValue is
  2191.          * a Vector orarray each element  added as a child, if childValue
  2192.          * is a Hashtable each key/value pair is added in the order that
  2193.          * Enumeration returns the keys.
  2194.          */
  2195.         protected void loadChildren() {
  2196.             loadedChildren = true;
  2197.             createChildren(this, childValue);
  2198.         }
  2199.     }
  2200.  
  2201. /////////////////
  2202. // Accessibility support
  2203. ////////////////
  2204.  
  2205.     /**
  2206.      * Get the AccessibleContext associated with this JComponent
  2207.      *
  2208.      * @return the AccessibleContext of this JComponent
  2209.      */
  2210.     public AccessibleContext getAccessibleContext() {
  2211.         if (accessibleContext == null) {
  2212.             accessibleContext = new AccessibleJTree();
  2213.         }
  2214.         return accessibleContext;
  2215.     }
  2216.  
  2217.     //
  2218.     // *** should also implement AccessibleAction (expansion/contraction)
  2219.     // *** and what's up with keyboard navigation/manipulation?
  2220.     //
  2221.     /**
  2222.      * The class used to obtain the accessible role for this object.
  2223.      * <p>
  2224.      * Warning: serialized objects of this class will not be compatible with
  2225.      * future swing releases.  The current serialization support is appropriate
  2226.      * for short term storage or RMI between Swing1.0 applications.  It will
  2227.      * not be possible to load serialized Swing1.0 objects with future releases
  2228.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  2229.      * baseline for the serialized form of Swing objects.
  2230.      */
  2231.     protected class AccessibleJTree extends AccessibleJComponent 
  2232.     implements AccessibleSelection, TreeModelListener, TreeExpansionListener  {
  2233.  
  2234.         public AccessibleJTree() {
  2235.            // Add a tree model listener for JTree
  2236.            JTree.this.getModel().addTreeModelListener(this);
  2237.            JTree.this.addTreeExpansionListener(this);      
  2238.         } 
  2239.  
  2240.         /**
  2241.          * Fire a visible data property change notification.
  2242.          *
  2243.          */
  2244.         public void fireVisibleDataPropertyChange() {
  2245.            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2246.                               new Boolean(false), new Boolean(true));
  2247.         }
  2248.  
  2249.         /**
  2250.          * Fire a selection property change notification.
  2251.          *
  2252.          */
  2253.         public void fireSelectionPropertyChange() {
  2254.            fireVisibleDataPropertyChange();
  2255.            firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2256.                               new Boolean(false), new Boolean(true));
  2257.         }
  2258.  
  2259.  
  2260.         // Fire the visible data changes for the model changes.
  2261.  
  2262.         /**
  2263.          * Tree Model Node change notification.
  2264.          *
  2265.          * @param e  a Tree Model event
  2266.          */
  2267.         public void treeNodesChanged(TreeModelEvent e) {
  2268.            fireVisibleDataPropertyChange();
  2269.         }
  2270.  
  2271.         /**
  2272.          * Tree Model Node change notification.
  2273.          *
  2274.          * @param e  a Tree node insertion event
  2275.          */
  2276.         public void treeNodesInserted(TreeModelEvent e) {
  2277.            fireVisibleDataPropertyChange();
  2278.         }
  2279.  
  2280.         /**
  2281.          * Tree Model Node change notification.
  2282.          *
  2283.          * @param e  a Tree node(s) removal event
  2284.          */
  2285.         public  void treeNodesRemoved(TreeModelEvent e) {
  2286.            fireVisibleDataPropertyChange();
  2287.         }
  2288.  
  2289.         /**
  2290.          * Tree Model structure change change notification.
  2291.          *
  2292.          * @param e  a Tree Model event
  2293.          */
  2294.         public  void treeStructureChanged(TreeModelEvent e) {
  2295.            fireVisibleDataPropertyChange();
  2296.         }
  2297.  
  2298.         /**
  2299.          * Tree Collapsed notification.
  2300.          *
  2301.          * @param e  a TreeExpansionEvent
  2302.          */
  2303.         public  void treeCollapsed(TreeExpansionEvent e) {
  2304.            fireVisibleDataPropertyChange();
  2305.         }
  2306.  
  2307.         /**
  2308.          * Tree Model Expansion notification.
  2309.          *
  2310.          * @param e  a Tree node insertion event
  2311.          */
  2312.         public  void treeExpanded(TreeExpansionEvent e) {
  2313.             fireVisibleDataPropertyChange();
  2314.          }
  2315.  
  2316.  
  2317.         private AccessibleContext getCurrentAccessibleContext() {
  2318.             Component c = getCurrentComponent();
  2319.             if (c instanceof Accessible) {
  2320.                 return (((Accessible) c).getAccessibleContext());
  2321.             } else {
  2322.                 return null;
  2323.             }
  2324.         }
  2325.  
  2326.         private Component getCurrentComponent() {
  2327.             // is the object visible?
  2328.             // if so, get row, selected, focus & leaf state, 
  2329.             // and then get the renderer component and return it
  2330.             TreeModel model = JTree.this.getModel();
  2331.             TreePath path = new TreePath(model.getRoot());
  2332.             if (JTree.this.isVisible(path)) {
  2333.                 TreeCellRenderer r = JTree.this.getCellRenderer();
  2334.                 TreeUI ui = JTree.this.getUI();
  2335.                 if (ui != null) {
  2336.                     int row = ui.getRowForPath(path);
  2337.                     boolean selected = JTree.this.isPathSelected(path);
  2338.                     boolean expanded = JTree.this.isExpanded(path);
  2339.                     boolean hasFocus = false; // how to tell?? -PK
  2340.                     return r.getTreeCellRendererComponent(JTree.this, 
  2341.                         model.getRoot(), selected, expanded, 
  2342.                         model.isLeaf(model.getRoot()), row, hasFocus);
  2343.                 }
  2344.             } 
  2345.             return null;
  2346.         }
  2347.  
  2348.         // Overridden methods from AccessibleJComponent
  2349.  
  2350.         /**
  2351.          * Get the Accessible name of this JTree.  This returns the name
  2352.          * of the top-most node in the tree
  2353.          *
  2354.          * @return the Accessible name of this JTree
  2355.          */
  2356.         public String getAccessibleName() {
  2357.             AccessibleContext ac = getCurrentAccessibleContext();
  2358.             if (ac != null) {
  2359.                 String name = ac.getAccessibleName();
  2360.                 if ((name != null) && (name != "")) {
  2361.                     return ac.getAccessibleName();
  2362.                 } else {
  2363.                     return null;
  2364.                 }
  2365.             }
  2366.             if ((accessibleName != null) && (accessibleName != "")) {
  2367.                 return accessibleName;
  2368.             } else {
  2369.                 return null;
  2370.             }
  2371.         }
  2372.  
  2373.         //
  2374.         // *** should check toolip text for desc. (needs MouseEvent)
  2375.         //
  2376.         public String getAccessibleDescription() {
  2377.             AccessibleContext ac = getCurrentAccessibleContext();
  2378.             if (ac != null) {
  2379.                 return ac.getAccessibleDescription();
  2380.             } else {
  2381.                 return super.getAccessibleDescription();
  2382.             }
  2383.         }
  2384.  
  2385.         /**
  2386.          * Get the role of this object.
  2387.          *
  2388.          * @return an instance of AccessibleRole describing the role of the 
  2389.          * object
  2390.          * @see AccessibleRole
  2391.          */
  2392.         public AccessibleRole getAccessibleRole() {
  2393.             return AccessibleRole.TREE;
  2394.         }
  2395.  
  2396.         /**
  2397.          * Returns the Accessible child, if one exists, contained at the local
  2398.          * coordinate Point.
  2399.          *
  2400.          * @param p point in local coordinates of the this Accessible
  2401.          * @return the Accessible, if it exists, at the specified location;
  2402.          * else null
  2403.          */
  2404.         public Accessible getAccessibleAt(Point p) {
  2405.             TreePath path = getClosestPathForLocation(p.x, p.y);
  2406.             if (path != null) {
  2407.                 return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  2408.             } else {
  2409.                 return null;
  2410.             }
  2411.         }
  2412.  
  2413.         /**
  2414.          * Returns the number of top-level children nodes of this 
  2415.          * JTree.  Each of these nodes may in turn have children nodes.
  2416.          *
  2417.          * @return the number of accessible children nodes in the tree.
  2418.          */
  2419.         public int getAccessibleChildrenCount() {
  2420.             TreeModel model = JTree.this.getModel();
  2421.             if (model != null) {
  2422.                 return model.getChildCount(model.getRoot());
  2423.             } else {
  2424.                 return 0;
  2425.             }
  2426.         }
  2427.  
  2428.         /**
  2429.          * Return the nth Accessible child of the object.
  2430.          *
  2431.          * @param i zero-based index of child
  2432.          * @return the nth Accessible child of the object
  2433.          */
  2434.         public Accessible getAccessibleChild(int i) {
  2435.             TreeModel model = JTree.this.getModel();
  2436.             if (model != null) {
  2437.                 if (i < 0 || i >= model.getChildCount(model.getRoot())) {
  2438.                     return null;
  2439.                 } else {
  2440.                     Object o = model.getChild(model.getRoot(), i);
  2441.                     Object[] objPath = {model.getRoot(), o};
  2442.                     TreePath path = new TreePath(objPath);
  2443.                     return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  2444.                 }
  2445.             }
  2446.             return null;
  2447.         }
  2448.  
  2449.  
  2450.         // AccessibleSelection methods
  2451.  
  2452.         public AccessibleSelection getAccessibleSelection() {
  2453.             return this;
  2454.         }
  2455.  
  2456.         /**
  2457.          * Returns the number of items currently selected.
  2458.          * If no items are selected, the return value will be 0.
  2459.          *
  2460.          * @return the number of items currently selected.
  2461.          */
  2462.         public int getAccessibleSelectionCount() {
  2463.             return JTree.this.getSelectionCount();
  2464.         }
  2465.  
  2466.         /**
  2467.          * Returns an Accessible representing the specified selected item
  2468.          * in the object.  If there isn't a selection, or there are 
  2469.          * fewer items selcted than the integer passed in, the return
  2470.          * value will be null.
  2471.          *
  2472.          * @param i the zero-based index of selected items
  2473.          * @return an Accessible containing the selected item
  2474.          */
  2475.         public Accessible getAccessibleSelection(int i) {
  2476.             TreePath[] paths = JTree.this.getSelectionPaths();
  2477.             if (i < 0 || i >= paths.length) {
  2478.                 return null;
  2479.             } else {
  2480.                 return new AccessibleJTreeNode(JTree.this, paths[i], JTree.this);
  2481.             }
  2482.         }
  2483.  
  2484.         /**
  2485.          * Returns true if the current child of this object is selected.
  2486.          *
  2487.          * @param i the zero-based index of the child in this Accessible object.
  2488.          * @see AccessibleContext#getAccessibleChild
  2489.          */
  2490.         public boolean isAccessibleChildSelected(int i) {
  2491.             TreePath[] paths = JTree.this.getSelectionPaths();
  2492.             TreeModel treeModel = JTree.this.getModel();
  2493.             Object o;
  2494.             for (int j = 0; j < paths.length; j++) {
  2495.                 o = paths[j].getLastPathComponent();
  2496.                 if (i == treeModel.getIndexOfChild(treeModel.getRoot(), o)) {
  2497.                     return true;
  2498.                 }
  2499.             }
  2500.             return false;
  2501.         }
  2502.  
  2503.         /**
  2504.          * Adds the specified selected item in the object to the object's
  2505.          * selection.  If the object supports multiple selections,
  2506.          * the specified item is added to any existing selection, otherwise
  2507.          * it replaces any existing selection in the object.  If the
  2508.          * specified item is already selected, this method has no effect.
  2509.          *
  2510.          * @param i the zero-based index of selectable items
  2511.          */
  2512.         public void addAccessibleSelection(int i) {
  2513.            TreeModel model = JTree.this.getModel();
  2514.            if (model != null) {
  2515.                if (i >= 0 && i < model.getChildCount(model.getRoot())) {
  2516.                    Object o = model.getChild(model.getRoot(), i);
  2517.                    Object[] objPath = {model.getRoot(), o};
  2518.                    TreePath path = new TreePath(objPath);
  2519.                    JTree.this.addSelectionPath(path);
  2520.                 }
  2521.             }
  2522.         }
  2523.  
  2524.         /**
  2525.          * Removes the specified selected item in the object from the object's
  2526.          * selection.  If the specified item isn't currently selected, this
  2527.          * method has no effect.
  2528.          *
  2529.          * @param i the zero-based index of selectable items
  2530.          */
  2531.         public void removeAccessibleSelection(int i) {
  2532.            TreeModel model = JTree.this.getModel();
  2533.            if (model != null) {
  2534.                if (i >= 0 && i < model.getChildCount(model.getRoot())) {
  2535.                    Object o = model.getChild(model.getRoot(), i);
  2536.                    Object[] objPath = {model.getRoot(), o};
  2537.                    TreePath path = new TreePath(objPath);
  2538.                    JTree.this.removeSelectionPath(path);
  2539.                 }
  2540.             }
  2541.         }
  2542.  
  2543.         /**
  2544.          * Clears the selection in the object, so that nothing in the
  2545.          * object is selected.
  2546.          */
  2547.         public void clearAccessibleSelection() {
  2548.             int childCount = getAccessibleChildrenCount();
  2549.             for (int i = 0; i < childCount; i++) {
  2550.                 removeAccessibleSelection(i);
  2551.             }
  2552.         }
  2553.  
  2554.         /**
  2555.          * Causes every selected item in the object to be selected
  2556.          * if the object supports multiple selections.
  2557.          */
  2558.         public void selectAllAccessibleSelection() {
  2559.             TreeModel model = JTree.this.getModel();
  2560.             if (model != null) {
  2561.                JTree.this.addSelectionInterval(0, model.getChildCount(model.getRoot())-1);
  2562.             }
  2563.         }
  2564.  
  2565.         /**
  2566.          *
  2567.          */
  2568.         protected class AccessibleJTreeNode extends AccessibleContext
  2569.             implements Accessible, AccessibleComponent, AccessibleSelection, 
  2570.             AccessibleAction {
  2571.  
  2572.             private JTree tree = null;
  2573.             private TreeModel treeModel = null;
  2574.             private Object obj = null;
  2575.             private Object objParent = null;
  2576.             private TreePath path = null;
  2577.             private Accessible accessibleParent = null;
  2578.             private int index = -1;
  2579.             private boolean isLeaf = false;
  2580.  
  2581.             /**
  2582.              *  Constructs an AccessibleJTreeNode
  2583.              */
  2584.             public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
  2585.                 tree = t;
  2586.                 path = p;
  2587.                 accessibleParent = ap;
  2588.                 treeModel = t.getModel();
  2589.                 obj = p.getLastPathComponent();
  2590.                 Object[] objPath = p.getPath();
  2591.                 if (objPath.length > 1) {
  2592.                     objParent = objPath[objPath.length-2];
  2593.                     if (treeModel != null) {
  2594.                         index = treeModel.getIndexOfChild(objParent, obj);
  2595.                     }
  2596.                     Object[] objParentPath = new Object[objPath.length-1];
  2597.                     java.lang.System.arraycopy(objPath, 0, objParentPath, 0, objPath.length-1);
  2598.                     TreePath parentPath = new TreePath(objParentPath);
  2599.                     this.setAccessibleParent(accessibleParent);
  2600.                 } else {
  2601.                     if (treeModel != null) {
  2602.                         index = treeModel.getIndexOfChild(treeModel.getRoot(), obj);
  2603.                         this.setAccessibleParent(tree);
  2604.                     }
  2605.                 }
  2606.                 if (treeModel != null) {
  2607.                     isLeaf = treeModel.isLeaf(obj);
  2608.                 }
  2609.             }
  2610.  
  2611.             private TreePath getChildTreePath(int i) {
  2612.                 // Tree nodes can't be so complex that they have
  2613.                 // two sets of children -> we're ignoring that case
  2614.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  2615.                     return null;
  2616.                 } else {
  2617.                     Object childObj = treeModel.getChild(obj, i);
  2618.                     Object[] objPath = path.getPath();
  2619.                     Object[] objChildPath = new Object[objPath.length+1];
  2620.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  2621.                     objChildPath[objChildPath.length-1] = childObj;
  2622.                     return new TreePath(objChildPath);
  2623.                 }
  2624.             }
  2625.  
  2626.             /**
  2627.              * Get the AccessibleContext associated with this tree node
  2628.              *
  2629.              * @return the AccessibleContext of this JComponent
  2630.              */
  2631.             public AccessibleContext getAccessibleContext() {
  2632.                 return this;
  2633.             }
  2634.  
  2635.             private AccessibleContext getCurrentAccessibleContext() {
  2636.                 Component c = getCurrentComponent();
  2637.                 if (c instanceof Accessible) {
  2638.                     return (((Accessible) c).getAccessibleContext());
  2639.                 } else {
  2640.                     return null;
  2641.                 }
  2642.             }
  2643.  
  2644.             private Component getCurrentComponent() {
  2645.                 // is the object visible?
  2646.                 // if so, get row, selected, focus & leaf state, 
  2647.                 // and then get the renderer component and return it
  2648.                 if (tree.isVisible(path)) {
  2649.                     TreeCellRenderer r = tree.getCellRenderer();
  2650.                     TreeUI ui = tree.getUI();
  2651.                     if (ui != null) {
  2652.                         int row = ui.getRowForPath(path);
  2653.                         boolean selected = tree.isPathSelected(path);
  2654.                         boolean expanded = tree.isExpanded(path);
  2655.                         boolean hasFocus = false; // how to tell?? -PK
  2656.                         return r.getTreeCellRendererComponent(tree, obj, 
  2657.                             selected, expanded, isLeaf, row, hasFocus);
  2658.                     }
  2659.                 } 
  2660.                 return null;
  2661.             }
  2662.  
  2663.         // AccessibleContext methods
  2664.     
  2665.              /**
  2666.               * Get the accessible name of this object.
  2667.               *
  2668.               * @return the localized name of the object; null if this 
  2669.               * object does not have a name
  2670.               */
  2671.              public String getAccessibleName() {
  2672.                 AccessibleContext ac = getCurrentAccessibleContext();
  2673.                 if (ac != null) {
  2674.                     String name = ac.getAccessibleName();
  2675.                     if ((name != null) && (name != "")) {
  2676.                         return ac.getAccessibleName();
  2677.                     } else {
  2678.                         return null;
  2679.                     }
  2680.                 }
  2681.                 if ((accessibleName != null) && (accessibleName != "")) {
  2682.                     return accessibleName;
  2683.                 } else {
  2684.                     return null;
  2685.                 }
  2686.             }
  2687.     
  2688.             /**
  2689.              * Set the localized accessible name of this object.
  2690.              *
  2691.              * @param s the new localized name of the object.
  2692.              */
  2693.             public void setAccessibleName(String s) {
  2694.                 AccessibleContext ac = getCurrentAccessibleContext();
  2695.                 if (ac != null) {
  2696.                     ac.setAccessibleName(s);
  2697.                 } else {
  2698.                     super.setAccessibleName(s);
  2699.                 }
  2700.             }
  2701.     
  2702.             //
  2703.             // *** should check toolip text for desc. (needs MouseEvent)
  2704.             //
  2705.             /**
  2706.              * Get the accessible description of this object.
  2707.              *
  2708.              * @return the localized description of the object; null if 
  2709.              * this object does not have a description
  2710.              */
  2711.             public String getAccessibleDescription() {
  2712.                 AccessibleContext ac = getCurrentAccessibleContext();
  2713.                 if (ac != null) {
  2714.                     return ac.getAccessibleDescription();
  2715.                 } else {
  2716.                     return super.getAccessibleDescription();
  2717.                 }
  2718.             }
  2719.     
  2720.             /**
  2721.              * Set the accessible description of this object.
  2722.              *
  2723.              * @param s the new localized description of the object
  2724.              */
  2725.             public void setAccessibleDescription(String s) {
  2726.                 AccessibleContext ac = getCurrentAccessibleContext();
  2727.                 if (ac != null) {
  2728.                     ac.setAccessibleDescription(s);
  2729.                 } else {
  2730.                     super.setAccessibleDescription(s);
  2731.                 }
  2732.             }
  2733.     
  2734.             /**
  2735.              * Get the role of this object.
  2736.              *
  2737.              * @return an instance of AccessibleRole describing the role of the object
  2738.              * @see AccessibleRole
  2739.              */
  2740.             public AccessibleRole getAccessibleRole() {
  2741.                 AccessibleContext ac = getCurrentAccessibleContext();
  2742.                 if (ac != null) {
  2743.                     return ac.getAccessibleRole();
  2744.                 } else {
  2745.                     return AccessibleRole.UNKNOWN;
  2746.                 }
  2747.             }
  2748.     
  2749.             /**
  2750.              * Get the state set of this object.
  2751.              *
  2752.              * @return an instance of AccessibleStateSet containing the 
  2753.              * current state set of the object
  2754.              * @see AccessibleState
  2755.              */
  2756.             public AccessibleStateSet getAccessibleStateSet() {
  2757.                 AccessibleContext ac = getCurrentAccessibleContext();
  2758.                 AccessibleStateSet states;
  2759.                 if (ac != null) {
  2760.                     states = ac.getAccessibleStateSet();
  2761.                 } else {
  2762.                     states = new AccessibleStateSet();
  2763.                 }
  2764.                 // need to test here, 'cause the underlying component 
  2765.                 // is a cellRenderer, which is never showing...
  2766.                 if (isShowing()) {
  2767.                     states.add(AccessibleState.SHOWING);
  2768.                 } else if (states.contains(AccessibleState.SHOWING)) {
  2769.                     states.remove(AccessibleState.SHOWING);
  2770.                 }
  2771.                 if (isVisible()) {
  2772.                     states.add(AccessibleState.VISIBLE);
  2773.                 } else if (states.contains(AccessibleState.VISIBLE)) {
  2774.                     states.remove(AccessibleState.VISIBLE);
  2775.                 }
  2776.                 if (tree.isPathSelected(path)){
  2777.                     states.add(AccessibleState.SELECTED);
  2778.                 }
  2779.                 if (!isLeaf) {
  2780.                     states.add(AccessibleState.EXPANDABLE);
  2781.                 }
  2782.                 if (tree.isExpanded(path)) {
  2783.                     states.add(AccessibleState.EXPANDED);
  2784.                 } else {
  2785.                     states.add(AccessibleState.COLLAPSED);
  2786.                 }
  2787.                 if (tree.isEditable()) {
  2788.                     states.add(AccessibleState.EDITABLE);
  2789.                 }
  2790.                 return states;
  2791.             }
  2792.     
  2793.             /**
  2794.              * Get the Accessible parent of this object.
  2795.              *
  2796.              * @return the Accessible parent of this object; null if this
  2797.              * object does not have an Accessible parent
  2798.              */
  2799.             public Accessible getAccessibleParent() {
  2800.                 return accessibleParent;
  2801.             }
  2802.     
  2803.             /**
  2804.              * Get the index of this object in its accessible parent. 
  2805.              *
  2806.              * @return the index of this object in its parent; -1 if this 
  2807.              * object does not have an accessible parent.
  2808.              * @see #getAccessibleParent
  2809.              */
  2810.             public int getAccessibleIndexInParent() {
  2811.                 return index;
  2812.             }
  2813.     
  2814.             /**
  2815.              * Returns the number of accessible children in the object.
  2816.              *
  2817.              * @return the number of accessible children in the object.
  2818.              */
  2819.             public int getAccessibleChildrenCount() {
  2820.                 // Tree nodes can't be so complex that they have 
  2821.                 // two sets of children -> we're ignoring that case
  2822.                 return treeModel.getChildCount(obj);
  2823.             }
  2824.     
  2825.             /**
  2826.              * Return the specified Accessible child of the object.
  2827.              *
  2828.              * @param i zero-based index of child
  2829.              * @return the Accessible child of the object
  2830.              */
  2831.             public Accessible getAccessibleChild(int i) {
  2832.                 // Tree nodes can't be so complex that they have 
  2833.                 // two sets of children -> we're ignoring that case
  2834.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  2835.                     return null;
  2836.                 } else {
  2837.                     Object childObj = treeModel.getChild(obj, i);
  2838.                     Object[] objPath = path.getPath();
  2839.                     Object[] objChildPath = new Object[objPath.length+1];
  2840.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  2841.                     objChildPath[objChildPath.length-1] = childObj;
  2842.                     TreePath childPath = new TreePath(objChildPath);
  2843.                     return new AccessibleJTreeNode(JTree.this, childPath, this);
  2844.                 }
  2845.             }
  2846.     
  2847.             /** 
  2848.              * Gets the locale of the component. If the component does not have a 
  2849.              * locale, then the locale of its parent is returned.  
  2850.              *
  2851.              * @return This component's locale. If this component does not have a locale, the locale of its parent is returned.
  2852.              * @exception IllegalComponentStateException 
  2853.              * If the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
  2854.              * determined from the containing parent. 
  2855.              * @see setLocale
  2856.              */
  2857.             public Locale getLocale() {
  2858.                 AccessibleContext ac = getCurrentAccessibleContext();
  2859.                 if (ac != null) {
  2860.                     return ac.getLocale();
  2861.                 } else {
  2862.                     return tree.getLocale();
  2863.                 }
  2864.             }
  2865.     
  2866.             /**
  2867.              * Add a PropertyChangeListener to the listener list.
  2868.              * The listener is registered for all properties.
  2869.              *
  2870.              * @param listener  The PropertyChangeListener to be added
  2871.              */
  2872.             public void addPropertyChangeListener(PropertyChangeListener l) {
  2873.                 AccessibleContext ac = getCurrentAccessibleContext();
  2874.                 if (ac != null) {
  2875.                     ac.addPropertyChangeListener(l);
  2876.                 } else {
  2877.                     super.addPropertyChangeListener(l);
  2878.                 }
  2879.             }
  2880.     
  2881.             /**
  2882.              * Remove a PropertyChangeListener from the listener list.
  2883.              * This removes a PropertyChangeListener that was registered
  2884.              * for all properties.
  2885.              *
  2886.              * @param listener  The PropertyChangeListener to be removed
  2887.              */
  2888.             public void removePropertyChangeListener(PropertyChangeListener l) {
  2889.                 AccessibleContext ac = getCurrentAccessibleContext();
  2890.                 if (ac != null) {
  2891.                     ac.removePropertyChangeListener(l);
  2892.                 } else {
  2893.                     super.removePropertyChangeListener(l);
  2894.                 }
  2895.             }
  2896.     
  2897.             /**
  2898.              * Get the AccessibleAction associated with this object if one
  2899.              * exists.  Otherwise return null.
  2900.              *
  2901.              * @return the AccessibleAction, or null
  2902.              */
  2903.             public AccessibleAction getAccessibleAction() {
  2904.                 return this;
  2905.             }
  2906.  
  2907.             /**
  2908.              * Get the AccessibleComponent associated with this tree node
  2909.              * NOTE: if the node is not visible (either scrolled off of
  2910.              * the screen, or not expanded), this will return null
  2911.              *
  2912.              * @return the AccessibleComponent of this tree node
  2913.              */
  2914.             public AccessibleComponent getAccessibleComponent() {
  2915.                 return this; // to override getBounds()
  2916.             }
  2917.  
  2918.             /**
  2919.              * Get the AccessibleSelection associated with this object if one
  2920.              * exists.  Otherwise return null.
  2921.              *
  2922.              * @return the AccessibleSelection, or null
  2923.              */
  2924.             public AccessibleSelection getAccessibleSelection() {
  2925.                 AccessibleContext ac = getCurrentAccessibleContext();
  2926.                 if (ac != null && isLeaf) {
  2927.                     return getCurrentAccessibleContext().getAccessibleSelection();
  2928.                 } else {
  2929.                     return this;
  2930.                 }
  2931.             }
  2932.  
  2933.             /**
  2934.              * Get the AccessibleText associated with this object if one
  2935.              * exists.  Otherwise return null.
  2936.              *
  2937.              * @return the AccessibleText, or null
  2938.              */
  2939.             public AccessibleText getAccessibleText() {
  2940.                 AccessibleContext ac = getCurrentAccessibleContext();
  2941.                 if (ac != null) {
  2942.                     return getCurrentAccessibleContext().getAccessibleText();
  2943.                 } else {
  2944.                     return null;
  2945.                 }
  2946.             }
  2947.  
  2948.             /**
  2949.              * Get the AccessibleValue associated with this object if one
  2950.              * exists.  Otherwise return null.
  2951.              *
  2952.              * @return the AccessibleValue, or null
  2953.              */
  2954.             public AccessibleValue getAccessibleValue() {
  2955.                 AccessibleContext ac = getCurrentAccessibleContext();
  2956.                 if (ac != null) {
  2957.                     return getCurrentAccessibleContext().getAccessibleValue();
  2958.                 } else {
  2959.                     return null;
  2960.                 }
  2961.             }
  2962.  
  2963.  
  2964.         // AccessibleComponent methods
  2965.     
  2966.             /**
  2967.              * Get the background color of this object.
  2968.              *
  2969.              * @return the background color, if supported, of the object; 
  2970.              * otherwise, null
  2971.              */
  2972.             public Color getBackground() {
  2973.                 AccessibleContext ac = getCurrentAccessibleContext();
  2974.                 if (ac instanceof AccessibleComponent) {
  2975.                     return ((AccessibleComponent) ac).getBackground();
  2976.                 } else {
  2977.                     Component c = getCurrentComponent();
  2978.                     if (c != null) {
  2979.                         return c.getBackground();
  2980.                     } else {
  2981.                         return null;
  2982.                     }
  2983.                 }
  2984.             }
  2985.     
  2986.             /**
  2987.              * Set the background color of this object.
  2988.              *
  2989.              * @param c the new Color for the background
  2990.              */
  2991.             public void setBackground(Color c) {
  2992.                 AccessibleContext ac = getCurrentAccessibleContext();
  2993.                 if (ac instanceof AccessibleComponent) {
  2994.                     ((AccessibleComponent) ac).setBackground(c);
  2995.                 } else {
  2996.                     Component cp = getCurrentComponent();
  2997.                     if (cp != null) {
  2998.                         cp.setBackground(c);
  2999.                     }
  3000.                 }
  3001.             }
  3002.     
  3003.         
  3004.             /**
  3005.              * Get the foreground color of this object.
  3006.              *
  3007.              * @return the foreground color, if supported, of the object; 
  3008.              * otherwise, null
  3009.              */
  3010.             public Color getForeground() {
  3011.                 AccessibleContext ac = getCurrentAccessibleContext();
  3012.                 if (ac instanceof AccessibleComponent) {
  3013.                     return ((AccessibleComponent) ac).getForeground();
  3014.                 } else {
  3015.                     Component c = getCurrentComponent();
  3016.                     if (c != null) {
  3017.                         return c.getForeground();
  3018.                     } else {
  3019.                         return null;
  3020.                     }
  3021.                 }
  3022.             }
  3023.     
  3024.             public void setForeground(Color c) {
  3025.                 AccessibleContext ac = getCurrentAccessibleContext();
  3026.                 if (ac instanceof AccessibleComponent) {
  3027.                     ((AccessibleComponent) ac).setForeground(c);
  3028.                 } else {
  3029.                     Component cp = getCurrentComponent();
  3030.                     if (cp != null) {
  3031.                         cp.setForeground(c);
  3032.                     }
  3033.                 }
  3034.             }
  3035.     
  3036.             public Cursor getCursor() {
  3037.                 AccessibleContext ac = getCurrentAccessibleContext();
  3038.                 if (ac instanceof AccessibleComponent) {
  3039.                     return ((AccessibleComponent) ac).getCursor();
  3040.                 } else {
  3041.                     Component c = getCurrentComponent();
  3042.                     if (c != null) {
  3043.                         return c.getCursor();
  3044.                     } else {
  3045.                         Accessible ap = getAccessibleParent();
  3046.                         if (ap instanceof AccessibleComponent) {
  3047.                             return ((AccessibleComponent) ap).getCursor();
  3048.                         } else {
  3049.                             return null;
  3050.                         }
  3051.                     }
  3052.                 }
  3053.             }
  3054.     
  3055.             public void setCursor(Cursor c) {
  3056.                 AccessibleContext ac = getCurrentAccessibleContext();
  3057.                 if (ac instanceof AccessibleComponent) {
  3058.                     ((AccessibleComponent) ac).setCursor(c);
  3059.                 } else {
  3060.                     Component cp = getCurrentComponent();
  3061.                     if (cp != null) {
  3062.                         cp.setCursor(c);
  3063.                     }
  3064.                 }
  3065.             }
  3066.     
  3067.             public Font getFont() {
  3068.                 AccessibleContext ac = getCurrentAccessibleContext();
  3069.                 if (ac instanceof AccessibleComponent) {
  3070.                     return ((AccessibleComponent) ac).getFont();
  3071.                 } else {
  3072.                     Component c = getCurrentComponent();
  3073.                     if (c != null) {
  3074.                         return c.getFont();
  3075.                     } else {
  3076.                         return null;
  3077.                     }
  3078.                 }
  3079.             }
  3080.     
  3081.             public void setFont(Font f) {
  3082.                 AccessibleContext ac = getCurrentAccessibleContext();
  3083.                 if (ac instanceof AccessibleComponent) {
  3084.                     ((AccessibleComponent) ac).setFont(f);
  3085.                 } else {
  3086.                     Component c = getCurrentComponent();
  3087.                     if (c != null) {
  3088.                         c.setFont(f);
  3089.                     }
  3090.                 }
  3091.             }
  3092.     
  3093.             public FontMetrics getFontMetrics(Font f) {
  3094.                 AccessibleContext ac = getCurrentAccessibleContext();
  3095.                 if (ac instanceof AccessibleComponent) {
  3096.                     return ((AccessibleComponent) ac).getFontMetrics(f);
  3097.                 } else {
  3098.                     Component c = getCurrentComponent();
  3099.                     if (c != null) {
  3100.                         return c.getFontMetrics(f);
  3101.                     } else {
  3102.                         return null;
  3103.                     }
  3104.                 }
  3105.             }
  3106.     
  3107.             public boolean isEnabled() {
  3108.                 AccessibleContext ac = getCurrentAccessibleContext();
  3109.                 if (ac instanceof AccessibleComponent) {
  3110.                     return ((AccessibleComponent) ac).isEnabled();
  3111.                 } else {
  3112.                     Component c = getCurrentComponent();
  3113.                     if (c != null) {
  3114.                         return c.isEnabled();
  3115.                     } else {
  3116.                         return false;
  3117.                     }
  3118.                 }
  3119.             }
  3120.     
  3121.             public void setEnabled(boolean b) {
  3122.                 AccessibleContext ac = getCurrentAccessibleContext();
  3123.                 if (ac instanceof AccessibleComponent) {
  3124.                     ((AccessibleComponent) ac).setEnabled(b);
  3125.                 } else {
  3126.                     Component c = getCurrentComponent();
  3127.                     if (c != null) {
  3128.                         c.setEnabled(b);
  3129.                     }
  3130.                 }
  3131.             }
  3132.     
  3133.             public boolean isVisible() {
  3134.                 Rectangle pathBounds = tree.getPathBounds(path);
  3135.                 Rectangle parentBounds = tree.getVisibleRect();
  3136.                 if (pathBounds != null && parentBounds != null && 
  3137.                     parentBounds.intersects(pathBounds)) {
  3138.                     return true;
  3139.                 } else {
  3140.                     return false;
  3141.                 }
  3142.             }
  3143.     
  3144.             public void setVisible(boolean b) {
  3145.             }
  3146.     
  3147.             public boolean isShowing() {
  3148.                 return (tree.isShowing() && isVisible());
  3149.             }
  3150.     
  3151.             public boolean contains(Point p) {
  3152.                 AccessibleContext ac = getCurrentAccessibleContext();
  3153.                 if (ac instanceof AccessibleComponent) {
  3154.                     Rectangle r = ((AccessibleComponent) ac).getBounds();
  3155.                     return r.contains(p);
  3156.                 } else {
  3157.                     Component c = getCurrentComponent();
  3158.                     if (c != null) {
  3159.                         Rectangle r = c.getBounds();
  3160.                         return r.contains(p);
  3161.                     } else {
  3162.                         return getBounds().contains(p);
  3163.                     }
  3164.                 }
  3165.             }
  3166.     
  3167.             public Point getLocationOnScreen() {
  3168.                 if (tree != null) {
  3169.                     Point parentLocation = tree.getLocationOnScreen();
  3170.                     Point componentLocation = getLocation();
  3171.                     componentLocation.translate(parentLocation.x, parentLocation.y);
  3172.                     return componentLocation;
  3173.                 } else {
  3174.                     return null;
  3175.                 }
  3176.             }
  3177.     
  3178.             protected Point getLocationInJTree() {
  3179.                 Rectangle r = tree.getPathBounds(path);
  3180.                 if (r != null) {
  3181.                     return r.getLocation();
  3182.                 } else {
  3183.                     return null;
  3184.                 }
  3185.             }
  3186.  
  3187.             public Point getLocation() {
  3188.                 Rectangle r = getBounds();
  3189.                 if (r != null) {
  3190.                     return r.getLocation();
  3191.                 } else {
  3192.                     return null;
  3193.                 }
  3194.             }
  3195.     
  3196.             public void setLocation(Point p) {
  3197.             }
  3198.                 
  3199.             public Rectangle getBounds() {
  3200.                 Rectangle r = tree.getPathBounds(path);
  3201.                 Accessible parent = getAccessibleParent();
  3202.                 if (parent != null) {
  3203.                     if (parent instanceof AccessibleJTreeNode) {
  3204.                         Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();
  3205.                         if (parentLoc != null && r != null) {
  3206.                             r.translate(-parentLoc.x, -parentLoc.y);
  3207.                         } else {
  3208.                             return null;        // not visible!
  3209.                         }
  3210.                     } 
  3211.                 }
  3212.                 return r;
  3213.             }
  3214.     
  3215.             public void setBounds(Rectangle r) {
  3216.                 AccessibleContext ac = getCurrentAccessibleContext();
  3217.                 if (ac instanceof AccessibleComponent) {
  3218.                     ((AccessibleComponent) ac).setBounds(r);
  3219.                 } else {
  3220.                     Component c = getCurrentComponent();
  3221.                     if (c != null) {
  3222.                         c.setBounds(r);
  3223.                     }
  3224.                 }
  3225.             }
  3226.     
  3227.             public Dimension getSize() {
  3228.                 return getBounds().getSize();
  3229.             }
  3230.     
  3231.             public void setSize (Dimension d) {
  3232.                 AccessibleContext ac = getCurrentAccessibleContext();
  3233.                 if (ac instanceof AccessibleComponent) {
  3234.                     ((AccessibleComponent) ac).setSize(d);
  3235.                 } else {
  3236.                     Component c = getCurrentComponent();
  3237.                     if (c != null) {
  3238.                         c.setSize(d);
  3239.                     }
  3240.                 }
  3241.             }
  3242.     
  3243.             public Accessible getAccessibleAt(Point p) {
  3244.                 AccessibleContext ac = getCurrentAccessibleContext();
  3245.                 if (ac instanceof AccessibleComponent) {
  3246.                     return ((AccessibleComponent) ac).getAccessibleAt(p);
  3247.                 } else {
  3248.                     return null;
  3249.                 }
  3250.             }
  3251.     
  3252.             public boolean isFocusTraversable() {
  3253.                 AccessibleContext ac = getCurrentAccessibleContext();
  3254.                 if (ac instanceof AccessibleComponent) {
  3255.                     return ((AccessibleComponent) ac).isFocusTraversable();
  3256.                 } else {
  3257.                     Component c = getCurrentComponent();
  3258.                     if (c != null) {
  3259.                         return c.isFocusTraversable();
  3260.                     } else {
  3261.                         return false;
  3262.                     }
  3263.                 }
  3264.             }
  3265.     
  3266.             public void requestFocus() {
  3267.                 AccessibleContext ac = getCurrentAccessibleContext();
  3268.                 if (ac instanceof AccessibleComponent) {
  3269.                     ((AccessibleComponent) ac).requestFocus();
  3270.                 } else {
  3271.                     Component c = getCurrentComponent();
  3272.                     if (c != null) {
  3273.                         c.requestFocus();
  3274.                     }
  3275.                 }
  3276.             }
  3277.     
  3278.             public void addFocusListener(FocusListener l) {
  3279.                 AccessibleContext ac = getCurrentAccessibleContext();
  3280.                 if (ac instanceof AccessibleComponent) {
  3281.                     ((AccessibleComponent) ac).addFocusListener(l);
  3282.                 } else {
  3283.                     Component c = getCurrentComponent();
  3284.                     if (c != null) {
  3285.                         c.addFocusListener(l);
  3286.                     }
  3287.                 }
  3288.             }
  3289.     
  3290.             public void removeFocusListener(FocusListener l) {
  3291.                 AccessibleContext ac = getCurrentAccessibleContext();
  3292.                 if (ac instanceof AccessibleComponent) {
  3293.                     ((AccessibleComponent) ac).removeFocusListener(l);
  3294.                 } else {
  3295.                     Component c = getCurrentComponent();
  3296.                     if (c != null) {
  3297.                         c.removeFocusListener(l);
  3298.                     }
  3299.                 }
  3300.             }
  3301.  
  3302.         // AccessibleSelection methods
  3303.  
  3304.             /**
  3305.              * Returns the number of items currently selected.
  3306.              * If no items are selected, the return value will be 0.
  3307.              *
  3308.              * @return the number of items currently selected.
  3309.              */
  3310.             public int getAccessibleSelectionCount() {
  3311.                 int count = 0;
  3312.                 int childCount = getAccessibleChildrenCount();
  3313.                 for (int i = 0; i < childCount; i++) {
  3314.                     TreePath childPath = getChildTreePath(i);
  3315.                     if (tree.isPathSelected(childPath)) {
  3316.                        count++;
  3317.                     }
  3318.                 } 
  3319.                 return count;
  3320.             }
  3321.  
  3322.             /**
  3323.              * Returns an Accessible representing the specified selected item
  3324.              * in the object.  If there isn't a selection, or there are 
  3325.              * fewer items selcted than the integer passed in, the return
  3326.              * value will be null.
  3327.              *
  3328.              * @param i the zero-based index of selected items
  3329.              * @return an Accessible containing the selected item
  3330.              */
  3331.             public Accessible getAccessibleSelection(int i) {
  3332.                 int childCount = getAccessibleChildrenCount();
  3333.                 if (i < 0 || i >= childCount) {
  3334.                     return null;        // out of range
  3335.                 }
  3336.                 int count = 0;
  3337.                 for (int j = 0; j < childCount && i >= count; j++) {
  3338.                     TreePath childPath = getChildTreePath(j);
  3339.                     if (tree.isPathSelected(childPath)) { 
  3340.                         if (count == i) {
  3341.                             return new AccessibleJTreeNode(tree, childPath, this);
  3342.                         } else {
  3343.                             count++;
  3344.                         }
  3345.                     }
  3346.                 }
  3347.                 return null;
  3348.             }
  3349.  
  3350.             /**
  3351.              * Returns true if the current child of this object is selected.
  3352.              *
  3353.              * @param i the zero-based index of the child in this Accessible 
  3354.              * object.
  3355.              * @see AccessibleContext#getAccessibleChild
  3356.              */
  3357.             public boolean isAccessibleChildSelected(int i) {
  3358.                 int childCount = getAccessibleChildrenCount();
  3359.                 if (i < 0 || i >= childCount) {
  3360.                     return false;       // out of range
  3361.                 } else {
  3362.                     TreePath childPath = getChildTreePath(i);
  3363.                     return tree.isPathSelected(childPath);
  3364.                 }
  3365.             }
  3366.  
  3367.             /**
  3368.              * Adds the specified selected item in the object to the object's
  3369.              * selection.  If the object supports multiple selections,
  3370.              * the specified item is added to any existing selection, otherwise
  3371.              * it replaces any existing selection in the object.  If the
  3372.              * specified item is already selected, this method has no effect.
  3373.              *
  3374.              * @param i the zero-based index of selectable items
  3375.              */
  3376.             public void addAccessibleSelection(int i) {
  3377.                TreeModel model = JTree.this.getModel();
  3378.                if (model != null) {
  3379.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  3380.                        TreePath path = getChildTreePath(i);
  3381.                        JTree.this.addSelectionPath(path);
  3382.                     }
  3383.                 }
  3384.             }
  3385.  
  3386.             /**
  3387.              * Removes the specified selected item in the object from the 
  3388.              * object's
  3389.              * selection.  If the specified item isn't currently selected, this
  3390.              * method has no effect.
  3391.              *
  3392.              * @param i the zero-based index of selectable items
  3393.              */
  3394.             public void removeAccessibleSelection(int i) {
  3395.                TreeModel model = JTree.this.getModel();
  3396.                if (model != null) {
  3397.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  3398.                        TreePath path = getChildTreePath(i);
  3399.                        JTree.this.removeSelectionPath(path);
  3400.                     }
  3401.                 }
  3402.             }
  3403.  
  3404.             /**
  3405.              * Clears the selection in the object, so that nothing in the
  3406.              * object is selected.
  3407.              */
  3408.             public void clearAccessibleSelection() {
  3409.                 int childCount = getAccessibleChildrenCount();
  3410.                 for (int i = 0; i < childCount; i++) {
  3411.                     removeAccessibleSelection(i);
  3412.                 }
  3413.             }
  3414.  
  3415.             /**
  3416.              * Causes every selected item in the object to be selected
  3417.              * if the object supports multiple selections.
  3418.              */
  3419.             public void selectAllAccessibleSelection() {
  3420.                TreeModel model = JTree.this.getModel();
  3421.                if (model != null) {
  3422.                    int childCount = getAccessibleChildrenCount();
  3423.                    TreePath path;
  3424.                    for (int i = 0; i < childCount; i++) {
  3425.                        path = getChildTreePath(i);
  3426.                        JTree.this.addSelectionPath(path);
  3427.                    }
  3428.                 }
  3429.             }
  3430.  
  3431.         // AccessibleAction methods
  3432.  
  3433.             /**
  3434.              * Returns the number of accessible actions available in this 
  3435.              * tree node.  If this node is not a leaf, there is at least 
  3436.              * one action (toggle expand), in addition to any available
  3437.              * on the object behind the TreeCellRenderer.
  3438.              *
  3439.              * @return the number of Actions in this object
  3440.              */
  3441.             public int getAccessibleActionCount() {
  3442.                 AccessibleContext ac = getCurrentAccessibleContext();
  3443.                 if (ac != null) {
  3444.                     AccessibleAction aa = ac.getAccessibleAction();
  3445.                     if (aa != null) {
  3446.                         return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));
  3447.                     }
  3448.                 }
  3449.                 return isLeaf ? 0 : 1;
  3450.             }
  3451.  
  3452.             /**
  3453.              * Return a description of the specified action of the tree node.
  3454.              * If this node is not a leaf, there is at least one action
  3455.              * description (toggle expand), in addition to any available
  3456.              * on the object behind the TreeCellRenderer.
  3457.              *
  3458.              * @param i zero-based index of the actions
  3459.              * @return a description of the action
  3460.              */
  3461.             public String getAccessibleActionDescription(int i) {
  3462.                 if (i < 0 || i >= getAccessibleActionCount()) {
  3463.                     return null;
  3464.                 }
  3465.                 AccessibleContext ac = getCurrentAccessibleContext();
  3466.                 if (i == 0) {
  3467.                     return "toggle expand";
  3468.                 } else if (ac != null) {
  3469.                     AccessibleAction aa = ac.getAccessibleAction();
  3470.                     if (aa != null) {
  3471.                         return aa.getAccessibleActionDescription(i - 1);
  3472.                     }
  3473.                 }
  3474.                 return null;
  3475.             }
  3476.  
  3477.             /**
  3478.              * Perform the specified Action on the tree node.  If this node
  3479.              * is not a leaf, there is at least one action which can be
  3480.              * done (toggle expand), in addition to any available on the 
  3481.              * object behind the TreeCellRenderer.
  3482.              *
  3483.              * @param i zero-based index of actions
  3484.              * @return true if the the action was performed; else false.
  3485.              */
  3486.             public boolean doAccessibleAction(int i) {
  3487.                 if (i < 0 || i >= getAccessibleActionCount()) {
  3488.                     return false;
  3489.                 }
  3490.                 AccessibleContext ac = getCurrentAccessibleContext();
  3491.                 if (i == 0) {
  3492.                     if (JTree.this.isExpanded(path)) {
  3493.                         JTree.this.collapsePath(path);
  3494.                     } else {
  3495.                         JTree.this.expandPath(path);
  3496.                     }
  3497.                     return true;
  3498.                 } else if (ac != null) {
  3499.                     AccessibleAction aa = ac.getAccessibleAction();
  3500.                     if (aa != null) {
  3501.                         return aa.doAccessibleAction(i - 1);
  3502.                     }
  3503.                 }
  3504.                 return false;
  3505.             }
  3506.  
  3507.         } // inner class AccessibleJTreeNode
  3508.  
  3509.     }  // inner class AccessibleJTree
  3510.  
  3511. } // End of class JTree
  3512.  
  3513.